247 lines
7.4 KiB
Plaintext
247 lines
7.4 KiB
Plaintext
|
//------------------------------------------------------------------------------
|
||
|
// <copyright company='Microsoft Corporation'>
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// Information Contained Herein is Proprietary and Confidential.
|
||
|
// </copyright>
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
namespace Microsoft.Singularity.WebServer
|
||
|
{
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Globalization;
|
||
|
using System.Net;
|
||
|
using System.Net.Sockets;
|
||
|
using System.Text;
|
||
|
using System.Threading;
|
||
|
using System.Web;
|
||
|
|
||
|
// Singularity
|
||
|
using Microsoft.SingSharp;
|
||
|
using Microsoft.SingSharp.Runtime;
|
||
|
using Microsoft.Singularity.Channels;
|
||
|
//
|
||
|
|
||
|
internal sealed class Connection
|
||
|
{
|
||
|
private Listener! listener;
|
||
|
private Socket socket;
|
||
|
|
||
|
public Connection(Listener! listener, Socket! socket)
|
||
|
{
|
||
|
this.listener = listener;
|
||
|
this.socket = socket;
|
||
|
base();
|
||
|
}
|
||
|
|
||
|
public bool Connected
|
||
|
{
|
||
|
get {
|
||
|
return socket.Connected;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool IsLocal
|
||
|
{
|
||
|
get {
|
||
|
string remoteIP = RemoteIP;
|
||
|
|
||
|
if (remoteIP.Equals("127.0.0.1")) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (listener.ClientIP.Equals(remoteIP)) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//return false;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public string! LocalIP
|
||
|
{
|
||
|
get {
|
||
|
IPEndPoint endPoint = (IPEndPoint)socket.LocalEndPoint;
|
||
|
if ((endPoint != null) && (endPoint.Address != null)) {
|
||
|
return (!)endPoint.Address.ToString();
|
||
|
}
|
||
|
else {
|
||
|
return "127.0.0.1";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public string! RemoteIP
|
||
|
{
|
||
|
get {
|
||
|
IPEndPoint endPoint = (IPEndPoint)socket.RemoteEndPoint;
|
||
|
if ((endPoint != null) && (endPoint.Address != null)) {
|
||
|
return (!)endPoint.Address.ToString();
|
||
|
}
|
||
|
else {
|
||
|
// REVIEW: Is this correct? If RemoteEndPoint is not
|
||
|
// set, we end up returning 127.0.0.1 which is
|
||
|
// treated as localhost, and may not be what
|
||
|
// we want.
|
||
|
return "127.0.0.1";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public int ListenerPort
|
||
|
{
|
||
|
get {
|
||
|
return listener.Port;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Close()
|
||
|
{
|
||
|
try {
|
||
|
if (socket != null) // ROTORTODO
|
||
|
{
|
||
|
socket.Shutdown(SocketShutdown.Both);
|
||
|
socket.Close();
|
||
|
}
|
||
|
}
|
||
|
catch {
|
||
|
}
|
||
|
finally {
|
||
|
socket = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static String! MakeResponseHeaders(int statusCode, String moreHeaders, int contentLength, bool keepAlive)
|
||
|
{
|
||
|
StringBuilder sb = new StringBuilder();
|
||
|
|
||
|
sb.Append("HTTP/1.1 " + statusCode + " " + HttpWorkerRequest.GetStatusDescription(statusCode) + "\r\n");
|
||
|
sb.Append("Server: Microsoft VisualStudio .NET WebServer/" + Messages.VersionString + "\r\n");
|
||
|
sb.Append("Date: " + DateTime.Now.ToUniversalTime().ToString("R") + "\r\n");
|
||
|
if (contentLength >= 0)
|
||
|
sb.Append("Content-Length: " + contentLength + "\r\n");
|
||
|
if (moreHeaders != null)
|
||
|
sb.Append(moreHeaders);
|
||
|
if (!keepAlive)
|
||
|
sb.Append("Connection: Close\r\n");
|
||
|
sb.Append("\r\n");
|
||
|
|
||
|
return sb.ToString();
|
||
|
}
|
||
|
|
||
|
public byte[] ReadRequestBytes(int maxBytes)
|
||
|
{
|
||
|
try {
|
||
|
if (WaitForRequestBytes() == 0) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
int numBytes = socket.Available;
|
||
|
if (numBytes > maxBytes)
|
||
|
numBytes = maxBytes;
|
||
|
|
||
|
int numReceived = 0;
|
||
|
byte[] buffer = new byte[numBytes];
|
||
|
|
||
|
if (numBytes > 0) {
|
||
|
numReceived = socket.Receive(buffer, 0, numBytes, SocketFlags.None);
|
||
|
}
|
||
|
|
||
|
if (numReceived < numBytes) {
|
||
|
byte[] tempBuffer = new byte[numReceived];
|
||
|
|
||
|
if (numReceived > 0) {
|
||
|
Buffer.BlockCopy(buffer, 0, tempBuffer, 0, numReceived);
|
||
|
}
|
||
|
|
||
|
buffer = tempBuffer;
|
||
|
}
|
||
|
|
||
|
return buffer;
|
||
|
}
|
||
|
catch {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Write100Continue()
|
||
|
{
|
||
|
WriteEntireResponseFromString(100, null, null, true);
|
||
|
}
|
||
|
|
||
|
public void WriteBody(byte[] data, int offset, int length)
|
||
|
{
|
||
|
socket.Send(data, offset, length, SocketFlags.None);
|
||
|
}
|
||
|
|
||
|
public void WriteBody([Claims] byte[]! in ExHeap data)
|
||
|
{
|
||
|
socket.Send(data, SocketFlags.None);
|
||
|
}
|
||
|
|
||
|
public void WriteEntireResponseFromString(int statusCode, String extraHeaders, String body, bool keepAlive)
|
||
|
{
|
||
|
try {
|
||
|
int bodyLength = (body != null) ? Encoding.UTF8.GetByteCount(body) : 0;
|
||
|
string headers = MakeResponseHeaders(statusCode, extraHeaders, bodyLength, keepAlive);
|
||
|
|
||
|
socket.Send(Encoding.UTF8.GetBytes(headers + body));
|
||
|
}
|
||
|
catch (SocketException) {
|
||
|
}
|
||
|
finally {
|
||
|
if (!keepAlive) {
|
||
|
Close();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void WriteErrorAndClose(int statusCode, string message)
|
||
|
{
|
||
|
string body = Messages.FormatErrorMessageBody(statusCode);
|
||
|
if (message != null && message.Length > 0) {
|
||
|
body += "\r\n<!--\r\n" + message + "\r\n-->";
|
||
|
}
|
||
|
WriteEntireResponseFromString(statusCode, null, body, false);
|
||
|
}
|
||
|
|
||
|
public void WriteErrorAndClose(int statusCode)
|
||
|
{
|
||
|
WriteErrorAndClose(statusCode, null);
|
||
|
}
|
||
|
|
||
|
public int WaitForRequestBytes()
|
||
|
{
|
||
|
int availBytes = 0;
|
||
|
|
||
|
try {
|
||
|
if (socket.Available == 0) {
|
||
|
// poll until there is data
|
||
|
socket.Poll(100000 /* 100ms */, SelectMode.SelectRead);
|
||
|
if (socket.Available == 0 && socket.Connected) {
|
||
|
socket.Poll(10000000 /* 10sec */, SelectMode.SelectRead);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
availBytes = socket.Available;
|
||
|
}
|
||
|
catch {
|
||
|
}
|
||
|
|
||
|
return availBytes;
|
||
|
}
|
||
|
|
||
|
public void WriteHeaders(int statusCode, String extraHeaders)
|
||
|
{
|
||
|
string headers = MakeResponseHeaders(statusCode, extraHeaders, -1, false);
|
||
|
|
||
|
try {
|
||
|
socket.Send(Encoding.UTF8.GetBytes(headers));
|
||
|
}
|
||
|
catch (SocketException) {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|