Commit 2d880884 authored by titanium007's avatar titanium007

Fix POST chunked file upload

parent c084ccb6
...@@ -57,9 +57,9 @@ Sample request and response event handlers ...@@ -57,9 +57,9 @@ Sample request and response event handlers
{ {
Console.WriteLine(e.RequestURL); Console.WriteLine(e.RequestURL);
//modify request headers //read request headers
var requestHeaders = e.RequestHeaders; var requestHeaders = e.RequestHeaders;
if ((e.RequestMethod.ToUpper() == "POST" || e.RequestMethod.ToUpper() == "PUT") && e.RequestContentLength > 0) if ((e.RequestMethod.ToUpper() == "POST" || e.RequestMethod.ToUpper() == "PUT") && e.RequestContentLength > 0)
...@@ -87,9 +87,10 @@ Sample request and response event handlers ...@@ -87,9 +87,10 @@ Sample request and response event handlers
public void OnResponse(object sender, SessionEventArgs e) public void OnResponse(object sender, SessionEventArgs e)
{ {
//modify response headers //read response headers
var responseHeaders = e.ResponseHeaders; var responseHeaders = e.ResponseHeaders;
if (e.ResponseStatusCode == HttpStatusCode.OK) if (e.ResponseStatusCode == HttpStatusCode.OK)
{ {
if (e.ResponseContentType.Trim().ToLower().Contains("text/html")) if (e.ResponseContentType.Trim().ToLower().Contains("text/html"))
...@@ -101,7 +102,7 @@ Sample request and response event handlers ...@@ -101,7 +102,7 @@ Sample request and response event handlers
//Get response body as string //Get response body as string
string responseBody = e.GetResponseBodyAsString(); string responseBody = e.GetResponseBodyAsString();
//Inject script in to body //Modify e.ServerResponse
Regex rex = new Regex("</body>", RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Multiline); Regex rex = new Regex("</body>", RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Multiline);
string modified = rex.Replace(responseBody, "<script type =\"text/javascript\">alert('Response was modified by this script!');</script></body>", 1); string modified = rex.Replace(responseBody, "<script type =\"text/javascript\">alert('Response was modified by this script!');</script></body>", 1);
......
...@@ -60,10 +60,10 @@ namespace Titanium.Web.Proxy.Test ...@@ -60,10 +60,10 @@ namespace Titanium.Web.Proxy.Test
Console.WriteLine(e.RequestURL); Console.WriteLine(e.RequestURL);
////modify request headers ////read request headers
//var requestHeaders = e.RequestHeaders; //var requestHeaders = e.RequestHeaders;
//if ((e.RequestMethod.ToUpper() == "POST" || e.RequestMethod.ToUpper() == "PUT") && e.RequestContentLength > 0) //if ((e.RequestMethod.ToUpper() == "POST" || e.RequestMethod.ToUpper() == "PUT"))
//{ //{
// //Get/Set request body bytes // //Get/Set request body bytes
// byte[] bodyBytes = e.GetRequestBody(); // byte[] bodyBytes = e.GetRequestBody();
...@@ -89,9 +89,9 @@ namespace Titanium.Web.Proxy.Test ...@@ -89,9 +89,9 @@ namespace Titanium.Web.Proxy.Test
//Insert script to read the Browser URL and send it back to proxy //Insert script to read the Browser URL and send it back to proxy
public void OnResponse(object sender, SessionEventArgs e) public void OnResponse(object sender, SessionEventArgs e)
{ {
////modify response headers ////read response headers
//var responseHeaders = e.ResponseHeaders; //var responseHeaders = e.ResponseHeaders;
//if (e.ResponseStatusCode == HttpStatusCode.OK) //if (e.ResponseStatusCode == HttpStatusCode.OK)
//{ //{
......
...@@ -21,6 +21,14 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -21,6 +21,14 @@ namespace Titanium.Web.Proxy.EventArguments
internal CustomBinaryReader clientStreamReader { get; set; } internal CustomBinaryReader clientStreamReader { get; set; }
internal StreamWriter clientStreamWriter { get; set; } internal StreamWriter clientStreamWriter { get; set; }
internal bool isHttps { get; set; }
internal string requestURL { get; set; }
internal string requestHostname { get; set; }
internal int clientPort { get; set; }
internal IPAddress clientIpAddress { get; set; }
internal Encoding requestEncoding { get; set; } internal Encoding requestEncoding { get; set; }
internal Version requestHttpVersion { get; set; } internal Version requestHttpVersion { get; set; }
internal bool requestIsAlive { get; set; } internal bool requestIsAlive { get; set; }
...@@ -28,25 +36,19 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -28,25 +36,19 @@ namespace Titanium.Web.Proxy.EventArguments
internal byte[] requestBody { get; set; } internal byte[] requestBody { get; set; }
internal string requestBodyString { get; set; } internal string requestBodyString { get; set; }
internal bool requestBodyRead { get; set; } internal bool requestBodyRead { get; set; }
internal List<HttpHeader> requestHeaders { get; set; }
internal bool RequestLocked { get; set; }
internal HttpWebRequest proxyRequest { get; set; }
internal Encoding responseEncoding { get; set; } internal Encoding responseEncoding { get; set; }
internal Stream responseStream { get; set; } internal Stream responseStream { get; set; }
internal byte[] responseBody { get; set; } internal byte[] responseBody { get; set; }
internal string responseBodyString { get; set; } internal string responseBodyString { get; set; }
internal bool responseBodyRead { get; set; } internal bool responseBodyRead { get; set; }
internal List<HttpHeader> responseHeaders { get; set; }
internal bool RequestLocked { get; set; }
internal HttpWebRequest proxyRequest { get; set; }
internal bool ResponseLocked { get; set; } internal bool ResponseLocked { get; set; }
internal HttpWebResponse serverResponse { get; set; } internal HttpWebResponse serverResponse { get; set; }
internal bool isHttps { get; set; }
internal string requestURL { get; set; }
internal string requestHostname { get; set; }
internal int clientPort { get; set; }
internal IPAddress clientIpAddress { get; set; }
public int ClientPort { get { return this.clientPort; } } public int ClientPort { get { return this.clientPort; } }
public IPAddress ClientIpAddress { get { return this.clientIpAddress; } } public IPAddress ClientIpAddress { get { return this.clientIpAddress; } }
...@@ -56,14 +58,17 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -56,14 +58,17 @@ namespace Titanium.Web.Proxy.EventArguments
public string RequestURL { get { return this.requestURL; } } public string RequestURL { get { return this.requestURL; } }
public string RequestHostname { get { return this.requestHostname; } } public string RequestHostname { get { return this.requestHostname; } }
public List<HttpHeader> RequestHeaders { get { return this.requestHeaders; } }
public List<HttpHeader> ResponseHeaders { get { return this.responseHeaders; } }
public int RequestContentLength public int RequestContentLength
{ {
get get
{ {
if (this.RequestHeaders.Any(x => x.Name.ToLower() == "content-length")) if (this.requestHeaders.Any(x => x.Name.ToLower() == "content-length"))
{ {
int contentLen; int contentLen;
int.TryParse(this.RequestHeaders.First(x => x.Name.ToLower() == "content-length").Value, out contentLen); int.TryParse(this.requestHeaders.First(x => x.Name.ToLower() == "content-length").Value, out contentLen);
if (contentLen != 0) if (contentLen != 0)
return contentLen; return contentLen;
} }
...@@ -72,11 +77,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -72,11 +77,11 @@ namespace Titanium.Web.Proxy.EventArguments
} }
public string RequestMethod { get { return this.proxyRequest.Method; } } public string RequestMethod { get { return this.proxyRequest.Method; } }
public List<HttpHeader> RequestHeaders { get; set; }
public HttpStatusCode ResponseStatusCode { get { return this.serverResponse.StatusCode; } } public HttpStatusCode ResponseStatusCode { get { return this.serverResponse.StatusCode; } }
public string ResponseContentType { get { return this.ResponseHeaders.Any(x => x.Name.ToLower() == "content-type") ? this.ResponseHeaders.First(x => x.Name.ToLower() == "content-type").Value : null; } } public string ResponseContentType { get { return this.responseHeaders.Any(x => x.Name.ToLower() == "content-type") ? this.responseHeaders.First(x => x.Name.ToLower() == "content-type").Value : null; } }
public List<HttpHeader> ResponseHeaders { get; set; }
internal SessionEventArgs(int bufferSize) internal SessionEventArgs(int bufferSize)
{ {
...@@ -85,9 +90,88 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -85,9 +90,88 @@ namespace Titanium.Web.Proxy.EventArguments
private void readRequestBody() private void readRequestBody()
{ {
if ((proxyRequest.Method.ToUpper() != "POST" && proxyRequest.Method.ToUpper() != "PUT"))
{
throw new BodyNotFoundException("Request don't have a body." +
"Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body.");
}
if (requestBody == null) if (requestBody == null)
{ {
requestBody = clientStreamReader.ReadBytes(RequestContentLength); bool isChunked = false;
string requestContentEncoding = null;
if (requestHeaders.Any(x => x.Name.ToLower() == "content-encoding"))
{
requestContentEncoding = requestHeaders.First(x => x.Name.ToLower() == "content-encoding").Value;
}
if (requestHeaders.Any(x => x.Name.ToLower() == "transfer-encoding"))
{
var transferEncoding = requestHeaders.First(x => x.Name.ToLower() == "transfer-encoding").Value.ToLower();
if (transferEncoding.Contains("chunked"))
{
isChunked = true;
}
}
if (requestContentEncoding == null && !isChunked)
requestBody = clientStreamReader.ReadBytes(RequestContentLength);
else
{
using (var requestBodyStream = new MemoryStream())
{
if (isChunked)
{
while (true)
{
var chuchkHead = clientStreamReader.ReadLine();
var chunkSize = int.Parse(chuchkHead, System.Globalization.NumberStyles.HexNumber);
if (chunkSize != 0)
{
var buffer = clientStreamReader.ReadBytes(chunkSize);
requestBodyStream.Write(buffer, 0, buffer.Length);
var chunkTrail = clientStreamReader.ReadLine();
}
else
{
clientStreamReader.ReadLine();
break;
}
}
}
try
{
switch (requestContentEncoding)
{
case "gzip":
requestBody = CompressionHelper.DecompressGzip(requestBodyStream);
break;
case "deflate":
requestBody = CompressionHelper.DecompressDeflate(requestBodyStream);
break;
case "zlib":
requestBody = CompressionHelper.DecompressGzip(requestBodyStream);
break;
default:
requestBody = requestBodyStream.ToArray();
break;
}
}
catch {
requestBody = requestBodyStream.ToArray();
}
}
}
} }
requestBodyRead = true; requestBodyRead = true;
} }
...@@ -95,6 +179,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -95,6 +179,7 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
if (responseBody == null) if (responseBody == null)
{ {
switch (serverResponse.ContentEncoding) switch (serverResponse.ContentEncoding)
{ {
case "gzip": case "gzip":
...@@ -144,34 +229,25 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -144,34 +229,25 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server."); if (RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
if ((proxyRequest.Method.ToUpper() == "POST" || proxyRequest.Method.ToUpper() == "PUT") && RequestContentLength > 0) readRequestBody();
{ return requestBody;
readRequestBody();
return requestBody;
}
else
throw new BodyNotFoundException("Request don't have a body." +
"Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body.");
} }
public string GetRequestBodyAsString() public string GetRequestBodyAsString()
{ {
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server."); if (RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
if ((proxyRequest.Method.ToUpper() == "POST" || proxyRequest.Method.ToUpper() == "PUT") && RequestContentLength > 0)
{
readRequestBody();
if (requestBodyString == null) readRequestBody();
{
requestBodyString = requestEncoding.GetString(requestBody); if (requestBodyString == null)
} {
return requestBodyString; requestBodyString = requestEncoding.GetString(requestBody);
} }
else return requestBodyString;
throw new BodyNotFoundException("Request don't have a body." +
"Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body.");
} }
...@@ -302,7 +378,6 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -302,7 +378,6 @@ namespace Titanium.Web.Proxy.EventArguments
} }
} }
} }
\ No newline at end of file
...@@ -59,7 +59,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -59,7 +59,7 @@ namespace Titanium.Web.Proxy.Helpers
public static byte[] DecompressGzip(Stream input) public static byte[] DecompressGzip(Stream input)
{ {
using (System.IO.Compression.GZipStream decompressor = new System.IO.Compression.GZipStream(input, System.IO.Compression.CompressionMode.Decompress)) using (var decompressor = new System.IO.Compression.GZipStream(input, System.IO.Compression.CompressionMode.Decompress))
{ {
int read = 0; int read = 0;
......
...@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy ...@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy
httpRemoteUri = new Uri(httpCmdSplit[1]); httpRemoteUri = new Uri(httpCmdSplit[1]);
var httpVersion = httpCmdSplit[2]; var httpVersion = httpCmdSplit[2];
var excluded = ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x)); var excluded = ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x));
//Client wants to create a secure tcp tunnel (its a HTTPS request) //Client wants to create a secure tcp tunnel (its a HTTPS request)
...@@ -59,11 +59,11 @@ namespace Titanium.Web.Proxy ...@@ -59,11 +59,11 @@ namespace Titanium.Web.Proxy
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]); httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
clientStreamReader.ReadAllLines(); clientStreamReader.ReadAllLines();
WriteConnectResponse(clientStreamWriter, httpVersion); WriteConnectResponse(clientStreamWriter, httpVersion);
var certificate = ProxyServer.CertManager.CreateCertificate(httpRemoteUri.Host); var certificate = ProxyServer.CertManager.CreateCertificate(httpRemoteUri.Host);
SslStream sslStream = null; SslStream sslStream = null;
try try
...@@ -112,7 +112,7 @@ namespace Titanium.Web.Proxy ...@@ -112,7 +112,7 @@ namespace Titanium.Web.Proxy
} }
private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string secureTunnelHostName) private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string secureTunnelHostName)
{ {
...@@ -124,7 +124,7 @@ namespace Titanium.Web.Proxy ...@@ -124,7 +124,7 @@ namespace Titanium.Web.Proxy
var args = new SessionEventArgs(BUFFER_SIZE); var args = new SessionEventArgs(BUFFER_SIZE);
args.client = client; args.client = client;
try try
{ {
...@@ -150,26 +150,26 @@ namespace Titanium.Web.Proxy ...@@ -150,26 +150,26 @@ namespace Titanium.Web.Proxy
args.isHttps = true; args.isHttps = true;
} }
args.RequestHeaders = new List<HttpHeader>(); args.requestHeaders = new List<HttpHeader>();
string tmpLine = null; string tmpLine = null;
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine())) while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{ {
String[] header = tmpLine.Split(colonSpaceSplit, 2, StringSplitOptions.None); String[] header = tmpLine.Split(colonSpaceSplit, 2, StringSplitOptions.None);
args.RequestHeaders.Add(new HttpHeader(header[0], header[1])); args.requestHeaders.Add(new HttpHeader(header[0], header[1]));
} }
for (int i = 0; i < args.RequestHeaders.Count; i++) for (int i = 0; i < args.requestHeaders.Count; i++)
{ {
var rawHeader = args.RequestHeaders[i]; var rawHeader = args.requestHeaders[i];
//if request was upgrade to web-socket protocol then relay the request without proxying //if request was upgrade to web-socket protocol then relay the request without proxying
if ((rawHeader.Name.ToLower() == "upgrade") && (rawHeader.Value.ToLower() == "websocket")) if ((rawHeader.Name.ToLower() == "upgrade") && (rawHeader.Value.ToLower() == "websocket"))
{ {
TcpHelper.SendRaw(clientStreamReader.BaseStream, httpCmd, args.RequestHeaders, httpRemoteUri.Host, httpRemoteUri.Port, httpRemoteUri.Scheme == Uri.UriSchemeHttps); TcpHelper.SendRaw(clientStreamReader.BaseStream, httpCmd, args.requestHeaders, httpRemoteUri.Host, httpRemoteUri.Port, httpRemoteUri.Scheme == Uri.UriSchemeHttps);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return; return;
} }
...@@ -184,7 +184,7 @@ namespace Titanium.Web.Proxy ...@@ -184,7 +184,7 @@ namespace Titanium.Web.Proxy
args.proxyRequest.ProtocolVersion = version; args.proxyRequest.ProtocolVersion = version;
args.clientStream = clientStream; args.clientStream = clientStream;
args.clientStreamReader = clientStreamReader; args.clientStreamReader = clientStreamReader;
args.clientStreamWriter = clientStreamWriter; args.clientStreamWriter = clientStreamWriter;
args.proxyRequest.AllowAutoRedirect = false; args.proxyRequest.AllowAutoRedirect = false;
args.proxyRequest.AutomaticDecompression = DecompressionMethods.None; args.proxyRequest.AutomaticDecompression = DecompressionMethods.None;
args.requestHostname = args.proxyRequest.RequestUri.Host; args.requestHostname = args.proxyRequest.RequestUri.Host;
...@@ -195,7 +195,7 @@ namespace Titanium.Web.Proxy ...@@ -195,7 +195,7 @@ namespace Titanium.Web.Proxy
args.requestIsAlive = args.proxyRequest.KeepAlive; args.requestIsAlive = args.proxyRequest.KeepAlive;
args.proxyRequest.ConnectionGroupName = args.requestHostname; args.proxyRequest.ConnectionGroupName = args.requestHostname;
args.proxyRequest.AllowWriteStreamBuffering = true; args.proxyRequest.AllowWriteStreamBuffering = true;
//If requested interception //If requested interception
if (BeforeRequest != null) if (BeforeRequest != null)
...@@ -212,7 +212,7 @@ namespace Titanium.Web.Proxy ...@@ -212,7 +212,7 @@ namespace Titanium.Web.Proxy
return; return;
} }
SetRequestHeaders(args.RequestHeaders, args.proxyRequest); SetRequestHeaders(args.requestHeaders, args.proxyRequest);
//If request was modified by user //If request was modified by user
if (args.requestBodyRead) if (args.requestBodyRead)
...@@ -230,7 +230,6 @@ namespace Titanium.Web.Proxy ...@@ -230,7 +230,6 @@ namespace Titanium.Web.Proxy
if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT") if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT")
{ {
SendClientRequestBody(args); SendClientRequestBody(args);
} }
//Http request body sent, now wait asynchronously for response //Http request body sent, now wait asynchronously for response
args.proxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args); args.proxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
...@@ -267,79 +266,80 @@ namespace Titanium.Web.Proxy ...@@ -267,79 +266,80 @@ namespace Titanium.Web.Proxy
for (int i = 0; i < requestHeaders.Count; i++) for (int i = 0; i < requestHeaders.Count; i++)
{ {
switch (requestHeaders[i].Name.ToLower()) switch (requestHeaders[i].Name.ToLower())
{ {
case "accept": case "accept":
webRequest.Accept = requestHeaders[i].Value; webRequest.Accept = requestHeaders[i].Value;
break; break;
case "accept-encoding": case "accept-encoding":
webRequest.Headers.Add("Accept-Encoding", "gzip,deflate,zlib"); webRequest.Headers.Add("Accept-Encoding", "gzip,deflate,zlib");
break; break;
case "cookie": case "cookie":
webRequest.Headers["Cookie"] = requestHeaders[i].Value; webRequest.Headers["Cookie"] = requestHeaders[i].Value;
break; break;
case "connection": case "connection":
if (requestHeaders[i].Value.ToLower() == "keep-alive") if (requestHeaders[i].Value.ToLower() == "keep-alive")
webRequest.KeepAlive = true; webRequest.KeepAlive = true;
break;
case "content-length": break;
int contentLen; case "content-length":
int.TryParse(requestHeaders[i].Value, out contentLen); int contentLen;
if (contentLen != 0) int.TryParse(requestHeaders[i].Value, out contentLen);
webRequest.ContentLength = contentLen; if (contentLen != 0)
break; webRequest.ContentLength = contentLen;
case "content-type": break;
webRequest.ContentType = requestHeaders[i].Value; case "content-type":
break; webRequest.ContentType = requestHeaders[i].Value;
case "expect": break;
if (requestHeaders[i].Value.ToLower() == "100-continue") case "expect":
webRequest.ServicePoint.Expect100Continue = true; if (requestHeaders[i].Value.ToLower() == "100-continue")
else webRequest.ServicePoint.Expect100Continue = true;
webRequest.Expect = requestHeaders[i].Value; else
break; webRequest.Expect = requestHeaders[i].Value;
case "host": break;
webRequest.Host = requestHeaders[i].Value; case "host":
break; webRequest.Host = requestHeaders[i].Value;
case "if-modified-since": break;
String[] sb = requestHeaders[i].Value.Trim().Split(semiSplit); case "if-modified-since":
DateTime d; String[] sb = requestHeaders[i].Value.Trim().Split(semiSplit);
if (DateTime.TryParse(sb[0], out d)) DateTime d;
webRequest.IfModifiedSince = d; if (DateTime.TryParse(sb[0], out d))
break; webRequest.IfModifiedSince = d;
case "proxy-connection": break;
if (requestHeaders[i].Value.ToLower() == "keep-alive") case "proxy-connection":
webRequest.KeepAlive = true; if (requestHeaders[i].Value.ToLower() == "keep-alive")
break; webRequest.KeepAlive = true;
case "range": break;
var startEnd = requestHeaders[i].Value.Replace(Environment.NewLine, "").Remove(0, 6).Split('-'); case "range":
if (startEnd.Length > 1) { if (!String.IsNullOrEmpty(startEnd[1])) webRequest.AddRange(int.Parse(startEnd[0]), int.Parse(startEnd[1])); else webRequest.AddRange(int.Parse(startEnd[0])); } var startEnd = requestHeaders[i].Value.Replace(Environment.NewLine, "").Remove(0, 6).Split('-');
else if (startEnd.Length > 1) { if (!String.IsNullOrEmpty(startEnd[1])) webRequest.AddRange(int.Parse(startEnd[0]), int.Parse(startEnd[1])); else webRequest.AddRange(int.Parse(startEnd[0])); }
webRequest.AddRange(int.Parse(startEnd[0])); else
break; webRequest.AddRange(int.Parse(startEnd[0]));
case "referer": break;
webRequest.Referer = requestHeaders[i].Value; case "referer":
break; webRequest.Referer = requestHeaders[i].Value;
case "user-agent": break;
webRequest.UserAgent = requestHeaders[i].Value; case "user-agent":
break; webRequest.UserAgent = requestHeaders[i].Value;
break;
//revisit this, transfer-encoding is not a request header according to spec
//But how to identify if client is sending chunked body for PUT/POST? //revisit this, transfer-encoding is not a request header according to spec
case "transfer-encoding": //But how to identify if client is sending chunked body for PUT/POST?
if (requestHeaders[i].Value.ToLower() == "chunked") case "transfer-encoding":
webRequest.SendChunked = true; if (requestHeaders[i].Value.ToLower().Contains("chunked"))
else webRequest.SendChunked = true;
webRequest.SendChunked = false; else
break; webRequest.SendChunked = false;
case "upgrade": break;
if (requestHeaders[i].Value.ToLower() == "http/1.1") case "upgrade":
webRequest.Headers.Add("Upgrade", requestHeaders[i].Value); if (requestHeaders[i].Value.ToLower() == "http/1.1")
break; webRequest.Headers.Add("Upgrade", requestHeaders[i].Value);
break;
default:
webRequest.Headers.Add(requestHeaders[i].Name, requestHeaders[i].Value); default:
webRequest.Headers.Add(requestHeaders[i].Name, requestHeaders[i].Value);
break;
} break;
}
} }
...@@ -357,7 +357,7 @@ namespace Titanium.Web.Proxy ...@@ -357,7 +357,7 @@ namespace Titanium.Web.Proxy
args.proxyRequest.AllowWriteStreamBuffering = true; args.proxyRequest.AllowWriteStreamBuffering = true;
try try
{ {
int totalbytesRead = 0; int totalbytesRead = 0;
int bytesToRead; int bytesToRead;
...@@ -401,62 +401,31 @@ namespace Titanium.Web.Proxy ...@@ -401,62 +401,31 @@ namespace Titanium.Web.Proxy
else if (args.proxyRequest.SendChunked) else if (args.proxyRequest.SendChunked)
{ {
args.proxyRequest.AllowWriteStreamBuffering = true; args.proxyRequest.AllowWriteStreamBuffering = true;
try try
{ {
StringBuilder sb = new StringBuilder();
byte[] byteRead = new byte[1];
while (true) while (true)
{ {
var chuchkHead = args.clientStreamReader.ReadLine();
var chunkSize = int.Parse(chuchkHead, System.Globalization.NumberStyles.HexNumber);
args.clientStream.Read(byteRead, 0, 1); if (chunkSize != 0)
sb.Append(Encoding.ASCII.GetString(byteRead)); {
var buffer = args.clientStreamReader.ReadBytes(chunkSize);
postStream.Write(buffer, 0, buffer.Length);
if (sb.ToString().EndsWith(Environment.NewLine)) var chunkTrail = args.clientStreamReader.ReadLine();
}
else
{ {
var chunkSizeInHex = sb.ToString().Replace(Environment.NewLine, String.Empty); args.clientStreamReader.ReadLine();
var chunckSize = int.Parse(chunkSizeInHex, System.Globalization.NumberStyles.HexNumber);
if (chunckSize == 0)
{
for (int i = 0; i < Encoding.ASCII.GetByteCount(Environment.NewLine); i++)
{
args.clientStream.ReadByte();
}
break;
}
var totalbytesRead = 0;
int bytesToRead;
if (chunckSize < BUFFER_SIZE)
{
bytesToRead = chunckSize;
}
else
bytesToRead = BUFFER_SIZE;
while (totalbytesRead < chunckSize)
{
var buffer = args.clientStreamReader.ReadBytes(bytesToRead);
totalbytesRead += buffer.Length;
int RemainingBytes = chunckSize - totalbytesRead;
if (RemainingBytes < bytesToRead)
{
bytesToRead = RemainingBytes;
}
postStream.Write(buffer, 0, buffer.Length);
}
for (int i = 0; i < Encoding.ASCII.GetByteCount(Environment.NewLine); i++)
{
args.clientStream.ReadByte();
}
sb.Clear();
break;
} }
} }
postStream.Close(); postStream.Close();
} }
catch catch
...@@ -474,6 +443,6 @@ namespace Titanium.Web.Proxy ...@@ -474,6 +443,6 @@ namespace Titanium.Web.Proxy
} }
} }
} }
\ No newline at end of file
...@@ -38,10 +38,10 @@ namespace Titanium.Web.Proxy ...@@ -38,10 +38,10 @@ namespace Titanium.Web.Proxy
{ {
if (args.serverResponse != null) if (args.serverResponse != null)
{ {
args.ResponseHeaders = ReadResponseHeaders(args.serverResponse); args.responseHeaders = ReadResponseHeaders(args.serverResponse);
args.responseStream = args.serverResponse.GetResponseStream(); args.responseStream = args.serverResponse.GetResponseStream();
if (BeforeResponse != null) if (BeforeResponse != null)
{ {
args.responseEncoding = args.serverResponse.GetEncoding(); args.responseEncoding = args.serverResponse.GetEncoding();
...@@ -52,11 +52,11 @@ namespace Titanium.Web.Proxy ...@@ -52,11 +52,11 @@ namespace Titanium.Web.Proxy
if (args.responseBodyRead) if (args.responseBodyRead)
{ {
bool isChunked = args.ResponseHeaders.Any(x => x.Name.ToLower() == "transfer-encoding") == false ? false : args.ResponseHeaders.First(x => x.Name.ToLower() == "transfer-encoding").Value.ToLower() == "chunked" ? true : false; bool isChunked = args.serverResponse.GetResponseHeader("transfer-encoding") == null ? false : args.serverResponse.GetResponseHeader("transfer-encoding").ToLower().Contains("chunked") ? true : false;
var contentEncoding = args.ResponseHeaders.FirstOrDefault(x => x.Name.ToLower() == "content-encoding"); var contentEncoding = args.serverResponse.ContentEncoding;
if (contentEncoding != null) if (contentEncoding != null)
switch (contentEncoding.Value.ToLower()) switch (contentEncoding.ToLower())
{ {
case "gzip": case "gzip":
args.responseBody = CompressionHelper.CompressGzip(args.responseBody); args.responseBody = CompressionHelper.CompressGzip(args.responseBody);
...@@ -68,20 +68,20 @@ namespace Titanium.Web.Proxy ...@@ -68,20 +68,20 @@ namespace Titanium.Web.Proxy
args.responseBody = CompressionHelper.CompressZlib(args.responseBody); args.responseBody = CompressionHelper.CompressZlib(args.responseBody);
break; break;
default: default:
throw new Exception("Specified content-encoding header is not supported"); break;
} }
WriteResponseStatus(args.serverResponse.ProtocolVersion, args.serverResponse.StatusCode, args.serverResponse.StatusDescription, args.clientStreamWriter); WriteResponseStatus(args.serverResponse.ProtocolVersion, args.serverResponse.StatusCode, args.serverResponse.StatusDescription, args.clientStreamWriter);
WriteResponseHeaders(args.clientStreamWriter, args.ResponseHeaders, args.responseBody.Length, isChunked); WriteResponseHeaders(args.clientStreamWriter, args.responseHeaders, args.responseBody.Length, isChunked);
WriteResponseBody(args.clientStream, args.responseBody, isChunked); WriteResponseBody(args.clientStream, args.responseBody, isChunked);
} }
else else
{ {
bool isChunked = args.serverResponse.GetResponseHeader("transfer-encoding") == null ? false : args.serverResponse.GetResponseHeader("transfer-encoding").ToLower() == "chunked" ? true : false; bool isChunked = args.serverResponse.GetResponseHeader("transfer-encoding") == null ? false : args.serverResponse.GetResponseHeader("transfer-encoding").ToLower().Contains("chunked") ? true : false;
WriteResponseStatus(args.serverResponse.ProtocolVersion, args.serverResponse.StatusCode, args.serverResponse.StatusDescription, args.clientStreamWriter); WriteResponseStatus(args.serverResponse.ProtocolVersion, args.serverResponse.StatusCode, args.serverResponse.StatusDescription, args.clientStreamWriter);
WriteResponseHeaders(args.clientStreamWriter, args.ResponseHeaders); WriteResponseHeaders(args.clientStreamWriter, args.responseHeaders);
WriteResponseBody(args.responseStream, args.clientStream, isChunked); WriteResponseBody(args.responseStream, args.clientStream, isChunked);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment