private void ExtractHeaderField(string headerField) { if (headerField.StartsWith("Host: ")) //look for the host { this.requestedHost = headerField.Substring(6).Trim(); if (!this.ParentFrame.QuickParse) { base.Attributes.Add("Requested Host", headerField.Substring(6).Trim()); } } else if (headerField.StartsWith("User-Agent: ", StringComparison.OrdinalIgnoreCase)) { this.userAgentBanner = headerField.Substring(12).Trim(); if (!this.ParentFrame.QuickParse) { base.Attributes.Add("User-Agent", this.userAgentBanner = headerField.Substring(12).Trim()); } } else if (headerField.StartsWith("Server: ", StringComparison.OrdinalIgnoreCase)) { this.serverBanner = headerField.Substring(8).Trim(); if (!this.ParentFrame.QuickParse) { this.Attributes.Add("Server banner", this.serverBanner = headerField.Substring(8).Trim()); } } else if (headerField.StartsWith("Cookie: ", StringComparison.OrdinalIgnoreCase)) { //http://www.w3.org/Protocols/rfc2109/rfc2109 this.cookie = headerField.Substring(8).Trim(); if (!this.ParentFrame.QuickParse) { this.Attributes.Add("Cookie", this.cookie); } } else if (headerField.StartsWith("Set-Cookie: ", StringComparison.OrdinalIgnoreCase)) { if (String.IsNullOrEmpty(this.cookie)) { this.cookie = headerField.Substring(12).Trim(); } else { this.cookie += "; " + headerField.Substring(12).Trim(); } if (!this.ParentFrame.QuickParse) { this.Attributes.Add("Cookie", this.cookie); } } else if (headerField.StartsWith("Content-Type: ", StringComparison.OrdinalIgnoreCase)) { this.contentType = headerField.Substring(14).Trim(); } else if (headerField.StartsWith("Content-Length: ", StringComparison.OrdinalIgnoreCase)) { this.contentLength = Convert.ToInt32(headerField.Substring(16).Trim()); } else if (headerField.StartsWith("Content-Encoding: ", StringComparison.OrdinalIgnoreCase)) { this.contentEncoding = headerField.Substring(18).Trim(); } else if (headerField.StartsWith("Transfer-Encoding: ", StringComparison.OrdinalIgnoreCase)) { this.transferEncoding = headerField.Substring(19).Trim(); } else if (headerField.StartsWith("WWW-Authenticate: ", StringComparison.OrdinalIgnoreCase) && headerField.Contains("realm=\"")) { int realmStart = headerField.IndexOf("realm=\"") + 7; int realmEnd = headerField.IndexOf('\"', realmStart); if (realmStart >= 0 && realmEnd > 0) { this.wwwAuthenticateRealm = headerField.Substring(realmStart, realmEnd - realmStart).Trim(); } } /* * else if(headerField.StartsWith("WWW-Authenticate: Basic realm=", StringComparison.OrdinalIgnoreCase)) * this.wwwAuth0enticateBasicRealm=headerField.Substring(31, headerField.Length-32); * */ else if (headerField.StartsWith("Proxy-Authenticate: Basic realm=", StringComparison.OrdinalIgnoreCase)) { this.wwwAuthenticateRealm = headerField.Substring(33, headerField.Length - 34).Trim(); } else if (headerField.StartsWith("Authorization: Basic ", StringComparison.OrdinalIgnoreCase)) { try { string base64string = headerField.Substring(21).Trim(); Byte[] bArray = Convert.FromBase64String(base64string); StringBuilder sb = new StringBuilder(bArray.Length); foreach (byte b in bArray) { sb.Append((char)b); } //string s=System.Text.Encoding.Unicode.GetString(bArray); string s = sb.ToString(); if (s.Contains(":")) { this.authorizationCredentialsUsername = s.Substring(0, s.IndexOf(':')); if (s.IndexOf(':') + 1 < s.Length) { this.authorizationCredentailsPassword = s.Substring(s.IndexOf(':') + 1); } else { this.authorizationCredentailsPassword = ""; } } } catch (Exception e) { if (!this.ParentFrame.QuickParse) { this.ParentFrame.Errors.Add(new Frame.Error(this.ParentFrame, PacketStartIndex, this.PacketEndIndex, "Cannot parse credentials in HTTP Authorization (" + e.Message + ")")); } } } else if (headerField.StartsWith("Authorization: Digest ", StringComparison.OrdinalIgnoreCase)) { try { string authorizationString = headerField.Substring(22).Trim(); foreach (string keyValueString in authorizationString.Split(new char[] { ',' })) { //username="******" string[] parts = keyValueString.Split(new char[] { '=' }); if (parts.Length == 2) { /** * private string wwwAuthenticateRealm;//Used to be wwwAuthenticateBasicRealm * private string authorizationCredentialsUsername; * private string authorizationCredentailsPassword; **/ string name = parts[0].Trim(); string value = parts[1].Trim(new char[] { ' ', '\"', '\'' }); if (name.Equals("username", StringComparison.InvariantCultureIgnoreCase)) { this.authorizationCredentialsUsername = value; if (this.authorizationCredentailsPassword == null) { this.authorizationCredentailsPassword = "******"; } } else if (name.Equals("realm", StringComparison.InvariantCultureIgnoreCase)) { this.wwwAuthenticateRealm = value; } } } } catch (Exception e) { if (!this.ParentFrame.QuickParse) { this.ParentFrame.Errors.Add(new Frame.Error(this.ParentFrame, PacketStartIndex, this.PacketEndIndex, "Cannot parse credentials in HTTP Authorization (" + e.Message + ")")); } } } else if (headerField.StartsWith("Content-Disposition:", StringComparison.OrdinalIgnoreCase)) { this.contentDisposition = headerField.Substring(20).Trim(); if (headerField.Contains("filename=")) { string filename = headerField.Substring(headerField.IndexOf("filename=") + 9); filename = filename.Trim(); if (filename.StartsWith("\"") && filename.IndexOf('\"', 1) > 0)//get the string inside the quotations { filename = filename.Substring(1, filename.IndexOf('\"', 1) - 1); } if (filename.Length > 0) { this.contentDispositionFilename = filename; } } else if (headerField.Contains("filename*=")) { //Example: Content-Disposition: inline; filename*=UTF-8''944.png //rfc6266 specifies that filename-parm can be "filename*" "=" ext-value //rfc5987 sprcifies that ext-value = charset "'" [ language ] "'" value-chars int charsetIndex = headerField.IndexOf("filename*=") + 10; int quoteIndex = headerField.IndexOf('\'', charsetIndex); if (charsetIndex > 0 && quoteIndex > 0) { string charset = headerField.Substring(charsetIndex, quoteIndex - charsetIndex); try { Encoding encoding = System.Text.Encoding.GetEncoding(charset); int extValueIndex = headerField.IndexOf('\'', quoteIndex + 1) + 1; byte[] extValueBytes = System.Text.Encoding.Default.GetBytes(headerField.Substring(extValueIndex)); string filename = encoding.GetString(extValueBytes); filename = filename.Trim(); if (filename.StartsWith("\"") && filename.IndexOf('\"', 1) > 0)//get the string inside the quotations { filename = filename.Substring(1, filename.IndexOf('\"', 1) - 1); } if (filename.Length > 0) { this.contentDispositionFilename = filename; } } catch { } } } } else if (headerField.StartsWith("Content-Range: ", StringComparison.OrdinalIgnoreCase)) { //Content-Range: bytes 8621-23239/42941008 //Content-Range: bytes 21010-47021/47022 System.Text.RegularExpressions.Regex rangeRegEx = new System.Text.RegularExpressions.Regex(@"bytes (?<start>[0-9]+)-(?<end>[0-9]+)/(?<total>[0-9]+)$"); System.Text.RegularExpressions.Match rangeMatch = rangeRegEx.Match(headerField); if (rangeMatch.Success) { long start, end, total; if (Int64.TryParse(rangeMatch.Groups["start"].Value, out start) && Int64.TryParse(rangeMatch.Groups["end"].Value, out end) && Int64.TryParse(rangeMatch.Groups["total"].Value, out total)) { this.contentRange = new FileTransfer.ContentRange() { Start = start, End = end, Total = total }; } } } }
private HttpPacket(Frame parentFrame, int packetStartIndex, int packetEndIndex) : base(parentFrame, packetStartIndex, packetEndIndex, "HTTP") { /* * * generic-message = start-line * *(message-header CRLF) * CRLF * [ message-body ] * * start-line = Request-Line | Status-Line * * */ this.headerFields = new List <string>(); this.requestedHost = null; this.requestedFileName = null; this.userAgentBanner = null; this.statusCode = null; this.statusMessage = null; this.serverBanner = null; this.contentType = null; this.contentLength = -1;//instead of null this.contentEncoding = null; this.cookie = null; this.transferEncoding = null; this.wwwAuthenticateRealm = null; this.authorizationCredentialsUsername = null; this.authorizationCredentailsPassword = null; this.packetHeaderIsComplete = false; this.contentDispositionFilename = null; this.contentRange = null; int dataIndex = packetStartIndex; //a start-line string startLine = Utils.ByteConverter.ReadLine(parentFrame.Data, ref dataIndex); if (startLine == null) { throw new Exception("HTTP packet does not contain a valid start line. Probably a false HTTP positive"); } if (startLine.Length > 2048) { throw new Exception("HTTP start line is longer than 255 bytes. Probably a false HTTP positive"); } if (dataIndex > packetEndIndex) { throw new Exception("HTTP start line ends after packet end..."); } if (startLine.StartsWith("GET")) { this.messageTypeIsRequest = true; this.requestMethod = RequestMethods.GET; } else if (startLine.StartsWith("HEAD")) { this.messageTypeIsRequest = true; this.requestMethod = RequestMethods.HEAD; } else if (startLine.StartsWith("POST")) { this.messageTypeIsRequest = true; this.requestMethod = RequestMethods.POST; } else if (startLine.StartsWith("PUT")) { this.messageTypeIsRequest = true; this.requestMethod = RequestMethods.PUT; } else if (startLine.StartsWith("DELETE")) { this.messageTypeIsRequest = true; this.requestMethod = RequestMethods.DELETE; } else if (startLine.StartsWith("TRACE")) { this.messageTypeIsRequest = true; this.requestMethod = RequestMethods.TRACE; } else if (startLine.StartsWith("OPTIONS")) { this.messageTypeIsRequest = true; this.requestMethod = RequestMethods.OPTIONS; } else if (startLine.StartsWith("CONNECT")) { this.messageTypeIsRequest = true; this.requestMethod = RequestMethods.CONNECT; } else if (startLine.StartsWith("HTTP")) { this.messageTypeIsRequest = false; this.requestMethod = RequestMethods.none; } else { throw new Exception("Incorrect HTTP Message Type or Request Method"); } //zero or more header fields (also known as "headers") while (true) { string headerLine = Utils.ByteConverter.ReadLine(parentFrame.Data, ref dataIndex); if (headerLine == null) { break;//this.packetHeaderIsComplete will NOT be true! } else if (headerLine.Length > 0) { this.headerFields.Add(headerLine); ExtractHeaderField(headerLine); } else //headerLine.Length==0 { this.packetHeaderIsComplete = true;//the header is complete and that's enough break;//the for loop should stop now... } } //see if there is a message-body if (this.packetHeaderIsComplete && this.messageTypeIsRequest && (requestMethod == RequestMethods.HEAD || requestMethod == RequestMethods.GET)) { //this part is important in case there are chained (queued) requests as in HTTP 1.1 this.messageBody = null; this.PacketEndIndex = dataIndex - 1; } else if (this.packetHeaderIsComplete && dataIndex <= packetEndIndex)//we have a body! { if (this.contentLength > 0 && this.contentLength < packetEndIndex - dataIndex + 1) { this.messageBody = new byte[this.contentLength]; this.PacketEndIndex = dataIndex + this.contentLength - 1; } else { this.messageBody = new byte[packetEndIndex - dataIndex + 1]; } Array.Copy(parentFrame.Data, dataIndex, this.messageBody, 0, this.messageBody.Length); /* * for(int i=0; i<this.messageBody.Length; i++) * this.messageBody[i]=parentFrame.Data[dataIndex+i]; * */ } else { this.messageBody = null; } //now extract some interresting information from the packet if (this.messageTypeIsRequest) //REQUEST { if (this.requestMethod == RequestMethods.GET || this.requestMethod == RequestMethods.POST || this.requestMethod == RequestMethods.HEAD || this.requestMethod == RequestMethods.OPTIONS) { int requestUriOffset = this.requestMethod.ToString().Length + 1; string fileURI = startLine.Substring(requestUriOffset, startLine.Length - requestUriOffset); if (fileURI.Contains(" HTTP")) { fileURI = fileURI.Substring(0, fileURI.IndexOf(" HTTP")); } if (fileURI.Length > 0)//If it is the index-file the URI will be just "/" { this.requestedFileName = fileURI; } else { this.requestedFileName = null; } } /* * else if(this.requestMethod==RequestMethods.POST) { * string fileURI=startLine.Substring(5, startLine.Length-5); * if(fileURI.Contains(" HTTP")) { * fileURI=fileURI.Substring(0, fileURI.IndexOf(" HTTP")); * } * if(fileURI.Length>0) {//If it is the index-file the URI will be just "/" * this.requestedFileName=fileURI; * } * }*/ } else //REPLY { if (startLine.StartsWith("HTTP/1.")) { this.statusCode = startLine.Substring(9, 3); if (startLine.Length > 12) { this.statusMessage = startLine.Substring(12).Trim(); } } } }