public override Stream GetOutputStream(bool disableCompression = false) { bool gzipEnable = false; if (!m_IsHeaderSent) { Headers.Remove("Content-Length"); if (!disableCompression && AcceptedEncodings != null && AcceptedEncodings.Contains("gzip")) { gzipEnable = true; Headers["Content-Encoding"] = "gzip"; } SendHeaders(); } else { throw new InvalidOperationException(); } Stream stream = m_Output; if (gzipEnable) { stream = new GZipStream(stream, CompressionMode.Compress); } m_Output = null; return(stream); }
private static Http2Connection.Http2Stream TryReuseStream(string scheme, string host, int port) { string key = scheme + "://" + host + ":" + port.ToString(); Http2Connection.Http2Stream h2stream = null; RwLockedList <H2StreamInfo> streaminfo; if (m_H2StreamList.TryGetValue(key, out streaminfo)) { lock (streaminfo) { for (int i = 0; i < streaminfo.Count; ++i) { H2StreamInfo h2info = streaminfo[i]; if ((h2info.ValidUntil - Environment.TickCount) > 0 && h2info.Connection.AvailableStreams > 0) { h2info.ValidUntil = Environment.TickCount + 5000; h2stream = h2info.Connection.OpenClientStream(); } } } } return(h2stream); }
public override HttpResponse BeginResponse(HttpStatusCode statuscode, string statusDescription) { FinishRequestBody(); var res = new Http2Response(m_Stream, this, statuscode, statusDescription); m_Stream = null; return(res); }
public Http2Response(Http2Connection.Http2Stream output, HttpRequest request, HttpStatusCode statusCode, string statusDescription) : base(request, statusCode, statusDescription) { Headers["Content-Type"] = "text/html"; m_Output = output; MajorVersion = request.MajorVersion; MinorVersion = request.MinorVersion; StatusCode = statusCode; StatusDescription = statusDescription; }
public override Stream GetOutputStream(long contentLength) { if (!m_IsHeaderSent) { Headers["Content-Length"] = contentLength.ToString(); SendHeaders(); } else { throw new InvalidOperationException(); } Http2Connection.Http2Stream s = m_Output; m_Output = null; return(s); }
private static Http2Connection.Http2Stream OpenHttp2Stream( string scheme, string host, int port, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, RemoteCertificateValidationCallback remoteCertificateValidationCallback, bool enableIPv6) { Http2Connection.Http2Stream h2stream = TryReuseStream(scheme, host, port); if (h2stream != null) { return(h2stream); } Stream s; if (scheme == Uri.UriSchemeHttp) { s = new HttpStream(ConnectToTcp(host, port, enableIPv6)) { IsReusable = false }; } else if (scheme == Uri.UriSchemeHttps) { s = ConnectToSslServer(host, port, clientCertificates, enabledSslProtocols, checkCertificateRevocation, false, remoteCertificateValidationCallback, enableIPv6); } else { throw new NotSupportedException(); } var h2con = new Http2Connection(s, false); h2stream = h2con.OpenClientStream(); AddH2Connection(h2con, scheme, host, port); return(h2stream); }
private static Stream DoStreamRequestHttp2Response( Http2Connection.Http2Stream s, Request request, Uri uri, bool doPost) { Dictionary <string, string> rxheaders; if (doPost) { if (request.Expect100Continue) { rxheaders = s.ReceiveHeaders(); string status; if (!rxheaders.TryGetValue(":status", out status)) { s.SendRstStream(Http2Connection.Http2ErrorCode.ProtocolError); throw new BadHttpResponseException("Not a HTTP response"); } if (status != "100") { int statusCode; if (!int.TryParse(status, out statusCode)) { statusCode = 500; } request.StatusCode = (HttpStatusCode)statusCode; if (statusCode == 401 && request.Authorization != null && request.Authorization.CanHandleUnauthorized(rxheaders)) { using (GetResponseBodyStream(request, rxheaders, s)) { /* just consume it */ } throw new RedoAfter401Exception(); } if (statusCode == 401) { string data; if (rxheaders.TryGetValue("www-authenticate", out data)) { string authtype; Dictionary <string, string> authpara = ParseWWWAuthenticate(data, out authtype); if (authpara == null) { s.SendRstStream(Http2Connection.Http2ErrorCode.StreamClosed); throw new BadHttpResponseException("Invalid WWW-Authenticate"); } else if (request.IsExceptionDisabled()) { return(GetResponseBodyStream(request, rxheaders, s)); } else { string realm; if (!authpara.TryGetValue("realm", out realm)) { realm = string.Empty; } using (GetResponseBodyStream(request, rxheaders, s)) { /* just consume it */ } throw new HttpUnauthorizedException(authtype, realm, authpara); } } } if (request.IsExceptionDisabled()) { return(GetResponseBodyStream(request, rxheaders, s)); } else { using (GetResponseBodyStream(request, rxheaders, s)) { /* just consume it */ } throw new HttpException(statusCode, statusCode == 404 ? statusCode.ToString() + " (" + uri + ")" : statusCode.ToString()); } } } /* append request POST data */ request.RequestBodyDelegate(s); s.SendEndOfStream(); } s.ReadTimeout = request.TimeoutMs; rxheaders = s.ReceiveHeaders(); IDictionary <string, string> headers = request.Headers; if (headers != null) { headers.Clear(); foreach (KeyValuePair <string, string> kvp in rxheaders) { headers.Add(kvp.Key, kvp.Value); } } string statusVal; if (!rxheaders.TryGetValue(":status", out statusVal)) { s.SendRstStream(Http2Connection.Http2ErrorCode.ProtocolError); throw new BadHttpResponseException("Missing status"); } if (!statusVal.StartsWith("2")) { int statusCode; if (!int.TryParse(statusVal, out statusCode)) { statusCode = 500; } request.StatusCode = (HttpStatusCode)statusCode; if (statusCode == 401 && request.Authorization != null && request.Authorization.CanHandleUnauthorized(rxheaders)) { using (GetResponseBodyStream(request, rxheaders, s)) { /* just consume it */ } throw new RedoAfter401Exception(); } if (statusCode == 401) { string data; if (rxheaders.TryGetValue("www-authenticate", out data)) { string authtype; Dictionary <string, string> authpara = ParseWWWAuthenticate(data, out authtype); if (authpara == null) { s.SendRstStream(Http2Connection.Http2ErrorCode.StreamClosed); throw new BadHttpResponseException("Invalid WWW-Authenticate"); } else if (request.IsExceptionDisabled()) { return(GetResponseBodyStream(request, rxheaders, s)); } else { string realm; if (!authpara.TryGetValue("realm", out realm)) { realm = string.Empty; } using (GetResponseBodyStream(request, rxheaders, s)) { /* just consume it */ } throw new HttpUnauthorizedException(authtype, realm, authpara); } } } else { request.Authorization?.ProcessResponseHeaders(rxheaders); } if (request.IsExceptionDisabled()) { return(GetResponseBodyStream(request, rxheaders, s)); } else { using (GetResponseBodyStream(request, rxheaders, s)) { /* just consume it */ } throw new HttpException(statusCode, statusCode == 404 ? statusVal + " (" + uri + ")" : statusVal); } } else { request.StatusCode = (HttpStatusCode)int.Parse(statusVal); } request.Authorization?.ProcessResponseHeaders(rxheaders); return(GetResponseBodyStream(request, rxheaders, s)); }
private static Stream DoStreamRequestHttp2( Request request, Uri uri, Http2Connection.Http2Stream reuseStream = null) { bool doPost = false; string encval; redoafter401: var actheaders = new Dictionary <string, string>(); actheaders.Add(":method", request.Method); actheaders.Add(":scheme", uri.Scheme); actheaders.Add(":path", uri.PathAndQuery); if (uri.IsDefaultPort) { actheaders.Add(":authority", uri.Host); } else { actheaders.Add(":authority", $"{uri.Host}:{uri.Port}"); } IDictionary <string, string> headers = request.Headers; string content_type = request.RequestContentType; bool compressed = request.IsCompressed; bool expect100Continue = request.Expect100Continue; if (headers != null) { foreach (KeyValuePair <string, string> k in headers) { string kn = k.Key.ToLower(); if (kn == "content-length" || kn == "content-type" || kn == "connection" || kn == "expect") { continue; } actheaders.Add(kn, k.Value); } } if (request.Authorization != null) { request.Authorization.GetRequestHeaders(actheaders, request.Method, uri.PathAndQuery); } if (actheaders.TryGetValue("transfer-encoding", out encval) && encval == "chunked") { actheaders.Remove("transfer-encoding"); } if (request.RequestBodyDelegate != null) { doPost = true; if (content_type != null) { actheaders.Add("content-type", content_type); } if (compressed && content_type != "application/x-gzip") { actheaders.Add("x-content-encoding", "gzip"); } if (expect100Continue) { actheaders.Add("expect", "100-continue"); } } if (request.Method != "HEAD") { actheaders.Add("Accept-Encoding", "gzip, deflate"); } int retrycnt = 1; retry: Http2Connection.Http2Stream s = reuseStream ?? OpenHttp2Stream(uri.Scheme, uri.Host, uri.Port, request.ClientCertificates, request.EnabledSslProtocols, request.CheckCertificateRevocation, request.RemoteCertificateValidationCallback, request.EnableIPv6 && OSSupportsIPv6); headers.Clear(); try { s.SendHeaders(actheaders, 0, !doPost); } catch (ObjectDisposedException) { if (retrycnt-- > 0) { goto retry; } throw; } catch (SocketException) { if (retrycnt-- > 0) { goto retry; } throw; } catch (IOException) { if (retrycnt-- > 0) { goto retry; } throw; } s.ReadTimeout = 10000; try { return(DoStreamRequestHttp2Response( s, request, uri, doPost)); } catch (RedoAfter401Exception) { goto redoafter401; } }
public static Stream ExecuteStreamRequest( this Request request) { byte[] postdata = request.RequestBody; if (postdata != null) { request.RequestContentLength = 0; if (request.IsCompressed || request.RequestContentType == "application/x-gzip") { using (var ms = new MemoryStream()) { using (var comp = new GZipStream(ms, CompressionMode.Compress)) { comp.Write(postdata, 0, postdata.Length); /* The GZIP stream has a CRC-32 and a EOF marker, so we close it first to have it completed */ } postdata = ms.ToArray(); } } request.RequestBodyDelegate = (Stream poststream) => poststream.Write(postdata, 0, postdata.Length); /* append request POST data */ request.RequestContentLength = postdata.Length; } string url = request.Url; if (request.GetValues != null) { url += "?" + BuildQueryString(request.GetValues); } var uri = new Uri(url); if (request.ConnectionMode == ConnectionModeEnum.Http2PriorKnowledge) { return(DoStreamRequestHttp2(request, uri)); } if (request.ConnectionMode == ConnectionModeEnum.UpgradeHttp2) { Http2Connection.Http2Stream h2stream = TryReuseStream(uri.Scheme, uri.Host, uri.Port); if (h2stream != null) { return(DoStreamRequestHttp2(request, uri, h2stream)); } } byte[] outdata; string method = request.Method; redoafter401: var reqdata = new StringBuilder(uri.IsDefaultPort ? $"{method} {uri.PathAndQuery} HTTP/1.1\r\nHost: {uri.Host}\r\n" : $"{method} {uri.PathAndQuery} HTTP/1.1\r\nHost: {uri.Host}:{uri.Port}\r\n"); bool doPost = false; bool doChunked = false; bool compressed = request.IsCompressed; int content_length = request.RequestContentLength; IDictionary <string, string> headers = request.Headers; bool haveAccept = false; if (headers != null) { var removal = new List <string>(); foreach (string k in headers.Keys) { if (string.Compare(k, "content-length", true) == 0 || string.Compare(k, "content-type", true) == 0 || string.Compare(k, "connection", true) == 0 || string.Compare(k, "expect", true) == 0 || string.Compare(k, "transfer-encoding", true) == 0) { removal.Add(k); } if (string.Compare(k, "accept", true) == 0) { haveAccept = true; } } if (removal.Count != 0) { foreach (string k in removal) { headers.Remove(k); } } } if (request.Authorization != null) { if (headers == null) { headers = new Dictionary <string, string>(); } if (request.Authorization.IsSchemeAllowed(uri.Scheme)) { request.Authorization.GetRequestHeaders(headers, request.Method, uri.PathAndQuery); } } if (headers != null) { foreach (KeyValuePair <string, string> kvp in headers) { reqdata.Append($"{kvp.Key}: {kvp.Value}\r\n"); } } if (request.UseChunkedEncoding) { reqdata.Append("Transfer-Encoding: chunked\r\n"); } string content_type = request.RequestContentType; bool expect100Continue = request.Expect100Continue; if (request.RequestBodyDelegate != null) { if (content_type != null) { reqdata.Append($"Content-Type: {content_type}\r\n"); } if (request.UseChunkedEncoding) { doPost = true; doChunked = true; reqdata.Append("Transfer-Encoding: chunked\r\n"); if (compressed && content_type != "application/x-gzip") { reqdata.Append("X-Content-Encoding: gzip\r\n"); } if (expect100Continue) { reqdata.Append("Expect: 100-continue\r\n"); } } else { doPost = true; if (content_length > request.Expect100ContinueMinSize) { expect100Continue = true; request.Expect100Continue = true; } reqdata.Append($"Content-Length: {content_length}\r\n"); if (compressed && content_type != "application/x-gzip") { reqdata.Append("X-Content-Encoding: gzip\r\n"); } if (expect100Continue) { reqdata.Append("Expect: 100-continue\r\n"); } } } if (method != "HEAD") { reqdata.Append("Accept-Encoding: gzip, deflate\r\n"); } if (!haveAccept) { reqdata.Append("Accept: */*\r\n"); } int retrycnt = 1; retry: AbstractHttpStream s = OpenStream(uri.Scheme, uri.Host, uri.Port, request.ClientCertificates, request.EnabledSslProtocols, request.CheckCertificateRevocation, request.ConnectionMode, request.RemoteCertificateValidationCallback, request.EnableIPv6 && OSSupportsIPv6); string finalreqdata = reqdata.ToString(); if (!s.IsReusable) { finalreqdata += "Connection: close\r\n"; } bool h2cUpgrade = request.ConnectionMode == ConnectionModeEnum.UpgradeHttp2; if (h2cUpgrade) { finalreqdata += "Upgrade: h2c\r\nHTTP2-Settings:\r\n"; } finalreqdata += "\r\n"; outdata = Encoding.ASCII.GetBytes(finalreqdata); try { s.Write(outdata, 0, outdata.Length); s.Flush(); } catch (ObjectDisposedException) { if (retrycnt-- > 0) { goto retry; } throw; } catch (SocketException) { if (retrycnt-- > 0) { goto retry; } throw; } catch (IOException) { if (retrycnt-- > 0) { goto retry; } throw; } s.ReadTimeout = 10000; string resline; string[] splits; if (doPost) { if (expect100Continue) { try { resline = s.ReadHeaderLine(); splits = resline.Split(new char[] { ' ' }, 3); if (splits.Length < 3) { throw new BadHttpResponseException("Not a HTTP response"); } if (!splits[0].StartsWith("HTTP/")) { throw new BadHttpResponseException("Missing HTTP version info"); } if (splits[1] == "101") { ReadHeaderLines(s, headers); headers.Clear(); var conn = new Http2Connection(s, false); Http2Connection.Http2Stream h2stream = conn.UpgradeClientStream(); AddH2Connection(conn, uri.Scheme, uri.Host, uri.Port); return(DoStreamRequestHttp2Response(h2stream, request, uri, doPost)); } if (splits[1] != "100") { int statusCode; headers.Clear(); ReadHeaderLines(s, headers); if (!int.TryParse(splits[1], out statusCode)) { statusCode = 500; } request.StatusCode = (HttpStatusCode)statusCode; if (statusCode == 401 && request.Authorization != null && request.Authorization.CanHandleUnauthorized(headers)) { using (GetResponseBodyStream(headers, uri, splits, method, s)) { /* just consume it */ } goto redoafter401; } if (statusCode == 401) { string data; if (headers.TryGetValue("www-authenticate", out data)) { string authtype; Dictionary <string, string> authpara = ParseWWWAuthenticate(data, out authtype); if (authpara == null) { using (GetResponseBodyStream(headers, uri, splits, method, s)) { /* just consume it */ } throw new BadHttpResponseException("Invalid WWW-Authenticate"); } else if (request.IsExceptionDisabled()) { return(GetResponseBodyStream(headers, uri, splits, method, s)); } else { string realm; if (!authpara.TryGetValue("realm", out realm)) { realm = string.Empty; } using (GetResponseBodyStream(headers, uri, splits, method, s)) { /* just consume it */ } throw new HttpUnauthorizedException(authtype, realm, authpara); } } } if (request.IsExceptionDisabled()) { return(GetResponseBodyStream(headers, uri, splits, method, s)); } else { using (GetResponseBodyStream(headers, uri, splits, method, s)) { /* just consume it */ } throw new HttpException(statusCode, statusCode == 404 ? splits[2] + " (" + url + ")" : splits[2]); } } while (s.ReadHeaderLine().Length != 0) { /* ReadHeaderLine() is all we have to do */ } } catch (HttpStream.TimeoutException) { /* keep caller from being exceptioned */ } catch (IOException) { /* keep caller from being exceptioned */ } catch (SocketException) { /* keep caller from being exceptioned */ } } if (doChunked) { /* append request POST data */ using (var reqbody = new HttpWriteChunkedBodyStream(s)) { request.RequestBodyDelegate(reqbody); } } else { /* append request POST data */ using (var reqbody = new RequestBodyStream(s, content_length)) { request.RequestBodyDelegate(reqbody); } } s.Flush(); } s.ReadTimeout = request.TimeoutMs; resline = s.ReadHeaderLine(); splits = resline.Split(new char[] { ' ' }, 3); if (splits.Length < 3) { throw new BadHttpResponseException("Not a HTTP response"); } if (!splits[0].StartsWith("HTTP/")) { throw new BadHttpResponseException("Missing HTTP version info"); } if (headers == null) { headers = new Dictionary <string, string>(); } else { headers.Clear(); } if (splits[1] == "101") { ReadHeaderLines(s, headers); headers.Clear(); var conn = new Http2Connection(s, false); Http2Connection.Http2Stream h2stream = conn.UpgradeClientStream(); AddH2Connection(conn, uri.Scheme, uri.Host, uri.Port); return(DoStreamRequestHttp2Response(h2stream, request, uri, doPost)); } if (!splits[1].StartsWith("2")) { ReadHeaderLines(s, headers); int statusCode; if (!int.TryParse(splits[1], out statusCode)) { statusCode = 500; } request.StatusCode = (HttpStatusCode)statusCode; if (statusCode == 401 && request.Authorization != null && request.Authorization.CanHandleUnauthorized(headers)) { using (GetResponseBodyStream(headers, uri, splits, method, s)) { /* just consume it */ } goto redoafter401; } if (statusCode == 401) { string data; if (headers.TryGetValue("www-authenticate", out data)) { string authtype; Dictionary <string, string> authpara = ParseWWWAuthenticate(data, out authtype); if (authpara == null) { using (GetResponseBodyStream(headers, uri, splits, method, s)) { /* just consume it */ } throw new BadHttpResponseException("Invalid WWW-Authenticate"); } else if (request.IsExceptionDisabled()) { return(GetResponseBodyStream(headers, uri, splits, method, s)); } else { string realm; if (!authpara.TryGetValue("realm", out realm)) { realm = string.Empty; } using (GetResponseBodyStream(headers, uri, splits, method, s)) { /* just consume it */ } throw new HttpUnauthorizedException(authtype, realm, authpara); } } } else { request.Authorization?.ProcessResponseHeaders(headers); } if (request.IsExceptionDisabled()) { return(GetResponseBodyStream(headers, uri, splits, method, s)); } else { using (GetResponseBodyStream(headers, uri, splits, method, s)) { /* just consume it */ } throw new HttpException(statusCode, statusCode == 404 ? splits[2] + " (" + url + ")" : splits[2]); } } else { request.StatusCode = (HttpStatusCode)int.Parse(splits[1]); } /* needs a little passthrough for not changing the API, this actually comes from HTTP/2 */ headers.Add(":status", splits[1]); ReadHeaderLines(s, headers); request.Authorization?.ProcessResponseHeaders(headers); return(GetResponseBodyStream(headers, uri, splits, method, s)); }
private static Stream GetResponseBodyStream(Request request, Dictionary <string, string> rxheaders, Http2Connection.Http2Stream s) { string value; string compressedresult = string.Empty; if (rxheaders.TryGetValue("content-encoding", out value) || rxheaders.TryGetValue("x-content-encoding", out value)) { /* Content-Encoding */ /* x-gzip is deprecated but better feel safe about having that */ if (value == "gzip" || value == "x-gzip") { compressedresult = "gzip"; } else if (value == "deflate") { compressedresult = "deflate"; } else { throw new NotSupportedException("Unsupport content-encoding"); } } if (request.Method == "HEAD") { /* HEAD does not have any response data */ return(s); } else { Stream bs = s; if (compressedresult.Length != 0) { if (compressedresult == "gzip") { bs = new GZipStream(bs, CompressionMode.Decompress); } else if (compressedresult == "deflate") { bs = new DeflateStream(bs, CompressionMode.Decompress); } } return(bs); } }
private void AcceptedConnection_Internal(Stream httpstream, string remoteAddr, bool isSsl, X509Certificate remoteCertificate) { Interlocked.Increment(ref m_AcceptedConnectionsCount); try { AddThread(Thread.CurrentThread); while (true) { HttpRequest req; try { req = new Http1Request(httpstream, remoteAddr, m_IsBehindProxy, isSsl, remoteCertificate); } catch (HttpResponse.ConnectionCloseException) { return; } catch (HttpStream.TimeoutException) { return; } catch (TimeoutException) { return; } catch (IOException) { return; } catch (InvalidDataException) { return; } catch (ObjectDisposedException) { return; } catch (SocketException) { return; } catch (Exception e) { m_Log.WarnFormat("Unexpected exception: {0}: {1}\n{2}", e.GetType().FullName, e.Message, e.StackTrace); return; } /* Recognition for HTTP/2.0 connection */ if (req.Method == "PRI") { if (req.MajorVersion != 2 || req.MinorVersion != 0) { req.SetConnectionClose(); req.ErrorResponse(HttpStatusCode.BadRequest, "Bad Request"); } else { X509Certificate cert = req.RemoteCertificate; req = null; /* no need for the initial request data */ HandleHttp2(new Http2Connection(httpstream, true), remoteAddr, isSsl, cert); } return; } else if (req.IsH2CUpgradable || req.IsH2CUpgradableAfterReadingBody) { Stream upgradeStream = null; if (req.IsH2CUpgradableAfterReadingBody) { upgradeStream = new MemoryStream(); req.Body.CopyTo(upgradeStream); upgradeStream.Seek(0, SeekOrigin.Begin); } httpstream.Write(m_H2cUpgrade, 0, m_H2cUpgrade.Length); byte[] settingsdata = FromUriBase64(req["http2-settings"]); var preface_receive = new byte[24]; if (24 != httpstream.Read(preface_receive, 0, 24)) { httpstream.Write(m_H2cGoAwayProtocolError, 0, m_H2cGoAwayProtocolError.Length); httpstream.Close(); upgradeStream?.Dispose(); return; } if (!preface_receive.SequenceEqual(m_H2cClientPreface)) { httpstream.Write(m_H2cGoAwayProtocolError, 0, m_H2cGoAwayProtocolError.Length); httpstream.Close(); upgradeStream?.Dispose(); return; } var h2con = new Http2Connection(httpstream, true); Http2Connection.Http2Stream h2stream = h2con.UpgradeStream(settingsdata, !req.IsH2CUpgradableAfterReadingBody && req.Expect100Continue); req = new Http2Request(h2stream, req.CallerIP, m_IsBehindProxy, isSsl, req.RemoteCertificate, req, upgradeStream); ThreadPool.UnsafeQueueUserWorkItem(HandleHttp2WorkItem, req); HandleHttp2(h2con, remoteAddr, isSsl, req.RemoteCertificate); return; } ProcessHttpRequest(req); } } catch (HttpStream.TimeoutException) { /* ignore */ } catch (Http2Connection.ConnectionClosedException) { /* HTTP/2 connection closed */ } catch (Http2Connection.ProtocolErrorException #if DEBUG e #endif ) { /* HTTP/2 protocol errors */ #if DEBUG m_Log.Debug("HTTP/2 Protocol Exception: ", e); #endif } catch (HttpResponse.DisconnectFromThreadException) { /* we simply disconnected that HttpRequest from HttpServer */ throw; } catch (HttpResponse.ConnectionCloseException) { /* simply a closed connection */ } catch (IOException) { /* commonly a broken pipe */ } catch (SocketException) { /* commonly a broken pipe */ } catch (ObjectDisposedException) { /* commonly a broken pipe */ } catch (Exception e) { m_Log.DebugFormat("Exception: {0}: {1}\n{2}", e.GetType().Name, e.Message, e.StackTrace); } finally { RemoveThread(Thread.CurrentThread); } }
public Http2Request(Http2Connection.Http2Stream stream, string callerIP, bool isBehindProxy, bool isSsl, X509Certificate remoteCertificate, HttpRequest upgradeReq = null, Stream upgradeBody = null) : base(isSsl, remoteCertificate) { MajorVersion = 2; MinorVersion = 0; m_Stream = stream; if (upgradeReq == null) { foreach (KeyValuePair <string, string> kvp in m_Stream.ReceiveHeaders()) { m_Headers[kvp.Key] = kvp.Value; } } else { foreach (KeyValuePair <string, string> kvp in upgradeReq.m_Headers) { m_Headers[kvp.Key] = kvp.Value; } m_Headers[":method"] = upgradeReq.Method; m_Headers[":path"] = upgradeReq.RawUrl; } string value; if (!m_Headers.TryGetValue(":method", out value)) { m_Stream.SendRstStream(Http2Connection.Http2ErrorCode.ProtocolError); throw new InvalidDataException(); } Method = value; if (!m_Headers.TryGetValue(":path", out value)) { m_Stream.SendRstStream(Http2Connection.Http2ErrorCode.ProtocolError); throw new InvalidDataException(); } RawUrl = value; ConnectionMode = HttpConnectionMode.Close; Expect100Continue = false; if (m_Headers.ContainsKey("expect") && m_Headers["expect"] == "100-continue") { Expect100Continue = true; } bool havePostData = false; if (upgradeReq != null && upgradeReq.IsH2CUpgradableAfterReadingBody) { /* skip following postdata handling here since it is already decoded */ m_Body = upgradeBody; } else if (m_Headers.ContainsKey("content-length") || m_Headers.ContainsKey("content-type") || m_Headers.ContainsKey("transfer-encoding")) { /* there is a body */ m_Body = new RequestBodyStream(this); if (m_Headers.ContainsKey("transfer-encoding")) { foreach (string transferEncoding in m_Headers["transfer-encoding"].Split(new char[] { '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries)) { if (transferEncoding == "gzip" || transferEncoding == "x-gzip") { m_Body = new GZipStream(m_Body, CompressionMode.Decompress); } else if (transferEncoding == "deflate") { m_Body = new DeflateStream(m_Body, CompressionMode.Decompress); } else { ConnectionMode = HttpConnectionMode.Close; ErrorResponse(HttpStatusCode.NotImplemented, "Transfer-Encoding " + transferEncoding + " not implemented"); throw new InvalidDataException(); } } } havePostData = true; } if (havePostData) { string contentEncoding = string.Empty; if (m_Headers.ContainsKey("content-encoding")) { contentEncoding = m_Headers["content-encoding"]; } else if (m_Headers.ContainsKey("x-content-encoding")) { contentEncoding = m_Headers["x-content-encoding"]; } else { contentEncoding = "identity"; } /* check for gzip encoding */ if (contentEncoding == "gzip" || contentEncoding == "x-gzip") /* x-gzip is deprecated as per RFC7230 but better accept it if sent */ { m_Body = new GZipStream(m_Body, CompressionMode.Decompress); } else if (contentEncoding == "deflate") { m_Body = new DeflateStream(m_Body, CompressionMode.Decompress); } else if (contentEncoding == "identity") { /* word is a synomyn for no-encoding so we use it for code simplification */ /* no additional action required, identity is simply transfer as-is */ } else { ConnectionMode = HttpConnectionMode.Close; ErrorResponse(HttpStatusCode.NotImplemented, "Content-Encoding not accepted"); throw new InvalidDataException(); } } CallerIP = (m_Headers.ContainsKey("x-forwarded-for") && isBehindProxy) ? m_Headers["x-forwarded-for"] : callerIP; }