byte [] GetHeaders() { var basicHeaders = new StringBuilder(); basicHeaders.Append(protocol); if (statusCode == 200) { basicHeaders.Append(" 200 "); } else { basicHeaders.Append(' '); basicHeaders.Append(statusCode.ToString(CultureInfo.InvariantCulture)); basicHeaders.Append(' '); } basicHeaders.Append(statusDescription); basicHeaders.Append("\r\nDate: "); basicHeaders.Append(DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture)); basicHeaders.Append(serverHeader); responseHeaders.Insert(0, basicHeaders.ToString()); if (!sentConnection) { if (!haveContentLength) { keepAlive = false; } AddConnectionHeader(); } responseHeaders.Append("\r\n"); return(HeaderEncoding.GetBytes(responseHeaders.ToString())); }
/// <devdoc> /// <para>Dumps a byte array to the log</para> /// </devdoc> internal static void Dump(TraceSource traceSource, object obj, string method, byte[] buffer, int offset, int length) { if (!ValidateSettings(traceSource, TraceEventType.Verbose)) { return; } if (buffer == null) { PrintLine(traceSource, TraceEventType.Verbose, 0, "(null)"); return; } if (offset > buffer.Length) { PrintLine(traceSource, TraceEventType.Verbose, 0, "(offset out of range)"); return; } PrintLine(traceSource, TraceEventType.Verbose, 0, "Data from " + GetObjectName(obj) + "#" + HashString(obj) + "::" + method); int maxDumpSize = GetMaxDumpSizeSetting(traceSource); if (length > maxDumpSize) { PrintLine(traceSource, TraceEventType.Verbose, 0, "(printing " + maxDumpSize.ToString(NumberFormatInfo.InvariantInfo) + " out of " + length.ToString(NumberFormatInfo.InvariantInfo) + ")"); length = maxDumpSize; } if ((length < 0) || (length > buffer.Length - offset)) { length = buffer.Length - offset; } if (GetUseProtocolTextSetting(traceSource)) { string output = "<<" + HeaderEncoding.GetString(buffer, offset, length) + ">>"; PrintLine(traceSource, TraceEventType.Verbose, 0, output); return; } do { int n = Math.Min(length, 16); string disp = String.Format(CultureInfo.CurrentCulture, "{0:X8} : ", offset); for (int i = 0; i < n; ++i) { disp += String.Format(CultureInfo.CurrentCulture, "{0:X2}", buffer[offset + i]) + ((i == 7) ? '-' : ' '); } for (int i = n; i < 16; ++i) { disp += " "; } disp += ": "; for (int i = 0; i < n; ++i) { disp += ((buffer[offset + i] < 0x20) || (buffer[offset + i] > 0x7e)) ? '.' : (char)(buffer[offset + i]); } PrintLine(traceSource, TraceEventType.Verbose, 0, disp); offset += n; length -= n; } while (length > 0); }
public override SecurityToken ReadToken(string tokenString) { // unbase64 header if necessary if (HeaderEncoding.IsBase64Encoded(tokenString)) { tokenString = HeaderEncoding.DecodeBase64(tokenString); } return(ReadToken(new XmlTextReader(new StringReader(tokenString)))); }
private void EnsureHeadersSent() { if (headers != null) { headers.Append("\r\n"); string str = headers.ToString(); byte[] data = HeaderEncoding.GetBytes(str); transport.SendOutput(requestId, requestNumber, data, data.Length); headers = null; } }
internal static string ParseHeaderEncoding(HeaderEncoding encoding) { if (encoding == HeaderEncoding.QuotedPrintable) { return("Q"); } else { return("B"); } }
/*++ * * ToByteArray() - * * Routine Description: * * Generates a byte array representation of the headers, that is ready to be sent. * So it Serializes our headers into a byte array suitable for sending over the net. * * the format looks like: * * Header-Name1: Header-Value1\r\n * Header-Name2: Header-Value2\r\n * ... * Header-NameN: Header-ValueN\r\n * \r\n * * Uses the ToString() method to generate, and then performs conversion. * * Performance Note: Why are we not doing a single copy/covert run? * As the code before used to know the size of the output! * Because according to Demitry, its cheaper to copy the headers twice, * then it is to call the UNICODE to ANSI conversion code many times. * * Arguments: * * None. * * Return Value: * * byte [] - array of bytes values * * --*/ /// <include file='doc\WebHeaders.uex' path='docs/doc[@for="WebHeaderCollection.ToByteArray"]/*' /> /// <internalonly/> /// <devdoc> /// <para> /// Obsolete. /// </para> /// </devdoc> public byte[] ToByteArray() { // Make sure the buffer is big enough. string tempStr = ToString(); // // Use the string of headers, convert to Char Array, // then convert to Bytes, // serializing finally into the buffer, along the way. // byte[] buffer = HeaderEncoding.GetBytes(tempStr); return(buffer); }
public override bool CanReadToken(string tokenString) { // unbase64 header if necessary if (HeaderEncoding.IsBase64Encoded(tokenString)) { tokenString = HeaderEncoding.DecodeBase64(tokenString); } if (tokenString.StartsWith("<")) { return(base.CanReadToken(new XmlTextReader(new StringReader(tokenString)))); } return(base.CanReadToken(tokenString)); }
byte [] GetHeaders() { responseHeaders.Insert(0, status); if (!sentConnection) { if (!haveContentLength) { keepAlive = false; } AddConnectionHeader(); } responseHeaders.Append("\r\n"); return(HeaderEncoding.GetBytes(responseHeaders.ToString())); }
// These methods require the HTTP_REQUEST to still be pinned in its original location. internal string?GetVerb() { var verb = NativeRequest->Verb; if (verb > HttpApiTypes.HTTP_VERB.HttpVerbUnknown && verb < HttpApiTypes.HTTP_VERB.HttpVerbMaximum) { return(HttpApiTypes.HttpVerbs[(int)verb]); } else if (verb == HttpApiTypes.HTTP_VERB.HttpVerbUnknown && NativeRequest->pUnknownVerb != null) { // Never use Latin1 for the VERB return(HeaderEncoding.GetString(NativeRequest->pUnknownVerb, NativeRequest->UnknownVerbLength, useLatin1: false)); } return(null); }
public override SecurityToken ReadToken(string tokenString) { // unbase64 header if necessary if (HeaderEncoding.IsBase64Encoded(tokenString)) { tokenString = HeaderEncoding.DecodeBase64(tokenString); } // check containing collection (mainly useful for chained EncryptedSecurityTokenHandler) if (ContainingCollection != null) { return(ContainingCollection.ReadToken(new XmlTextReader(new StringReader(tokenString)))); } else { return(ReadToken(new XmlTextReader(new StringReader(tokenString)))); } }
/// <summary> /// Get message body /// </summary> /// <returns></returns> public List <byte> GetBody() { var builder = new List <byte>(1024); // headers builder.AddRange(header.Encode(headerEncoding)); // delimeter builder.AddRange(HeaderEncoding.GetBytes(Util.CRLF)); if (IsMultipart) { builder.AddRange( Encoding.GetBytes("This is a multi-part message in MIME format." + Util.CRLF + Util.CRLF)); } builder.AddRange(GetBodyContent()); return(builder); }
internal unsafe void SerializeTrailers(HttpApiTypes.HTTP_DATA_CHUNK[] dataChunks, int currentChunk, List <GCHandle> pins) { Debug.Assert(currentChunk == dataChunks.Length - 1); Debug.Assert(HasTrailers); MakeTrailersReadOnly(); var trailerCount = 0; foreach (var trailerPair in Trailers) { trailerCount += trailerPair.Value.Count; } var pinnedHeaders = new List <GCHandle>(); var unknownHeaders = new HttpApiTypes.HTTP_UNKNOWN_HEADER[trailerCount]; var gcHandle = GCHandle.Alloc(unknownHeaders, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); dataChunks[currentChunk].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkTrailers; dataChunks[currentChunk].trailers.trailerCount = (ushort)trailerCount; dataChunks[currentChunk].trailers.pTrailers = gcHandle.AddrOfPinnedObject(); try { var unknownHeadersOffset = 0; foreach (var headerPair in Trailers) { if (headerPair.Value.Count == 0) { continue; } var headerName = headerPair.Key; var headerValues = headerPair.Value; for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++) { // Add Name var bytes = HeaderEncoding.GetBytes(headerName); unknownHeaders[unknownHeadersOffset].NameLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); unknownHeaders[unknownHeadersOffset].pName = (byte *)gcHandle.AddrOfPinnedObject(); // Add Value var headerValue = headerValues[headerValueIndex] ?? string.Empty; bytes = HeaderEncoding.GetBytes(headerValue); unknownHeaders[unknownHeadersOffset].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); unknownHeaders[unknownHeadersOffset].pRawValue = (byte *)gcHandle.AddrOfPinnedObject(); unknownHeadersOffset++; } } Debug.Assert(unknownHeadersOffset == trailerCount); } catch { FreePinnedHeaders(pinnedHeaders); throw; } // Success, keep the pins. pins.AddRange(pinnedHeaders); }
internal unsafe void SendError(ulong requestId, int httpStatusCode, IList <string>?authChallenges = null) { HttpApiTypes.HTTP_RESPONSE_V2 httpResponse = new HttpApiTypes.HTTP_RESPONSE_V2(); httpResponse.Response_V1.Version = new HttpApiTypes.HTTP_VERSION(); httpResponse.Response_V1.Version.MajorVersion = (ushort)1; httpResponse.Response_V1.Version.MinorVersion = (ushort)1; List <GCHandle>?pinnedHeaders = null; GCHandle gcHandle; try { // Copied from the multi-value headers section of SerializeHeaders if (authChallenges != null && authChallenges.Count > 0) { pinnedHeaders = new List <GCHandle>(authChallenges.Count + 3); HttpApiTypes.HTTP_RESPONSE_INFO[] knownHeaderInfo = new HttpApiTypes.HTTP_RESPONSE_INFO[1]; gcHandle = GCHandle.Alloc(knownHeaderInfo, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); httpResponse.pResponseInfo = (HttpApiTypes.HTTP_RESPONSE_INFO *)gcHandle.AddrOfPinnedObject(); knownHeaderInfo[httpResponse.ResponseInfoCount].Type = HttpApiTypes.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[httpResponse.ResponseInfoCount].Length = (uint)Marshal.SizeOf <HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS>(); HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS(); header.HeaderId = HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderWwwAuthenticate; header.Flags = HttpApiTypes.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // The docs say this is for www-auth only. HttpApiTypes.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApiTypes.HTTP_KNOWN_HEADER[authChallenges.Count]; gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); header.KnownHeaders = (HttpApiTypes.HTTP_KNOWN_HEADER *)gcHandle.AddrOfPinnedObject(); for (int headerValueIndex = 0; headerValueIndex < authChallenges.Count; headerValueIndex++) { // Add Value string headerValue = authChallenges[headerValueIndex]; byte[] bytes = HeaderEncoding.GetBytes(headerValue); nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); nativeHeaderValues[header.KnownHeaderCount].pRawValue = (byte *)gcHandle.AddrOfPinnedObject(); header.KnownHeaderCount++; } // This type is a struct, not an object, so pinning it causes a boxed copy to be created. We can't do that until after all the fields are set. gcHandle = GCHandle.Alloc(header, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); knownHeaderInfo[0].pInfo = (HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS *)gcHandle.AddrOfPinnedObject(); httpResponse.ResponseInfoCount = 1; } httpResponse.Response_V1.StatusCode = (ushort)httpStatusCode; string?statusDescription = HttpReasonPhrase.Get(httpStatusCode); uint dataWritten = 0; uint statusCode; byte[] byteReason = statusDescription != null?HeaderEncoding.GetBytes(statusDescription) : Array.Empty <byte>(); fixed(byte *pReason = byteReason) { httpResponse.Response_V1.pReason = (byte *)pReason; httpResponse.Response_V1.ReasonLength = (ushort)byteReason.Length; byte[] byteContentLength = new byte[] { (byte)'0' }; fixed(byte *pContentLength = byteContentLength) { (&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].pRawValue = (byte *)pContentLength; (&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].RawValueLength = (ushort)byteContentLength.Length; httpResponse.Response_V1.Headers.UnknownHeaderCount = 0; statusCode = HttpApi.HttpSendHttpResponse( _requestQueue.Handle, requestId, 0, &httpResponse, null, &dataWritten, IntPtr.Zero, 0, SafeNativeOverlapped.Zero, IntPtr.Zero); } } if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { // if we fail to send a 401 something's seriously wrong, abort the request HttpApi.HttpCancelHttpRequest(_requestQueue.Handle, requestId, IntPtr.Zero); } } finally { if (pinnedHeaders != null) { foreach (GCHandle handle in pinnedHeaders) { if (handle.IsAllocated) { handle.Free(); } } } } }
/* * 12.3 * HttpSendHttpResponse() and HttpSendResponseEntityBody() Flag Values. * The following flags can be used on calls to HttpSendHttpResponse() and HttpSendResponseEntityBody() API calls: * #define HTTP_SEND_RESPONSE_FLAG_DISCONNECT 0x00000001 #define HTTP_SEND_RESPONSE_FLAG_MORE_DATA 0x00000002 #define HTTP_SEND_RESPONSE_FLAG_RAW_HEADER 0x00000004 #define HTTP_SEND_RESPONSE_FLAG_VALID 0x00000007 * * HTTP_SEND_RESPONSE_FLAG_DISCONNECT: * specifies that the network connection should be disconnected immediately after * sending the response, overriding the HTTP protocol's persistent connection features. * HTTP_SEND_RESPONSE_FLAG_MORE_DATA: * specifies that additional entity body data will be sent by the caller. Thus, * the last call HttpSendResponseEntityBody for a RequestId, will have this flag reset. * HTTP_SEND_RESPONSE_RAW_HEADER: * specifies that a caller of HttpSendResponseEntityBody() is intentionally omitting * a call to HttpSendHttpResponse() in order to bypass normal header processing. The * actual HTTP header will be generated by the application and sent as entity body. * This flag should be passed on the first call to HttpSendResponseEntityBody, and * not after. Thus, flag is not applicable to HttpSendHttpResponse. */ // TODO: Consider using HTTP_SEND_RESPONSE_RAW_HEADER with HttpSendResponseEntityBody instead of calling HttpSendHttpResponse. // This will give us more control of the bytes that hit the wire, including encodings, HTTP 1.0, etc.. // It may also be faster to do this work in managed code and then pass down only one buffer. // What would we loose by bypassing HttpSendHttpResponse? // // TODO: Consider using the HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA flag for most/all responses rather than just Opaque. internal unsafe uint SendHeaders(HttpApiTypes.HTTP_DATA_CHUNK[]?dataChunks, ResponseStreamAsyncResult?asyncResult, HttpApiTypes.HTTP_FLAGS flags, bool isOpaqueUpgrade) { Debug.Assert(!HasStarted, "HttpListenerResponse::SendHeaders()|SentHeaders is true."); _responseState = ResponseState.Started; var reasonPhrase = GetReasonPhrase(StatusCode); uint statusCode; uint bytesSent; List <GCHandle>?pinnedHeaders = SerializeHeaders(isOpaqueUpgrade); try { if (dataChunks != null) { if (pinnedHeaders == null) { pinnedHeaders = new List <GCHandle>(); } var handle = GCHandle.Alloc(dataChunks, GCHandleType.Pinned); pinnedHeaders.Add(handle); _nativeResponse.Response_V1.EntityChunkCount = (ushort)dataChunks.Length; _nativeResponse.Response_V1.pEntityChunks = (HttpApiTypes.HTTP_DATA_CHUNK *)handle.AddrOfPinnedObject(); } else if (asyncResult != null && asyncResult.DataChunks != null) { _nativeResponse.Response_V1.EntityChunkCount = asyncResult.DataChunkCount; _nativeResponse.Response_V1.pEntityChunks = asyncResult.DataChunks; } else { _nativeResponse.Response_V1.EntityChunkCount = 0; _nativeResponse.Response_V1.pEntityChunks = null; } var cachePolicy = new HttpApiTypes.HTTP_CACHE_POLICY(); if (_cacheTtl.HasValue && _cacheTtl.Value > TimeSpan.Zero) { cachePolicy.Policy = HttpApiTypes.HTTP_CACHE_POLICY_TYPE.HttpCachePolicyTimeToLive; cachePolicy.SecondsToLive = (uint)Math.Min(_cacheTtl.Value.Ticks / TimeSpan.TicksPerSecond, Int32.MaxValue); } byte[] reasonPhraseBytes = HeaderEncoding.GetBytes(reasonPhrase); fixed(byte *pReasonPhrase = reasonPhraseBytes) { _nativeResponse.Response_V1.ReasonLength = (ushort)reasonPhraseBytes.Length; _nativeResponse.Response_V1.pReason = (byte *)pReasonPhrase; fixed(HttpApiTypes.HTTP_RESPONSE_V2 *pResponse = &_nativeResponse) { statusCode = HttpApi.HttpSendHttpResponse( RequestContext.Server.RequestQueue.Handle, Request.RequestId, (uint)flags, pResponse, &cachePolicy, &bytesSent, IntPtr.Zero, 0, asyncResult == null ? SafeNativeOverlapped.Zero : asyncResult.NativeOverlapped !, IntPtr.Zero); // GoAway is only supported on later versions. Retry. if (statusCode == ErrorCodes.ERROR_INVALID_PARAMETER && (flags & HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_GOAWAY) != 0) { flags &= ~HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_GOAWAY; statusCode = HttpApi.HttpSendHttpResponse( RequestContext.Server.RequestQueue.Handle, Request.RequestId, (uint)flags, pResponse, &cachePolicy, &bytesSent, IntPtr.Zero, 0, asyncResult == null ? SafeNativeOverlapped.Zero : asyncResult.NativeOverlapped !, IntPtr.Zero); // Succeeded without GoAway, disable them. if (statusCode != ErrorCodes.ERROR_INVALID_PARAMETER) { SupportsGoAway = false; } } if (asyncResult != null && statusCode == ErrorCodes.ERROR_SUCCESS && HttpSysListener.SkipIOCPCallbackOnSuccess) { asyncResult.BytesSent = bytesSent; // The caller will invoke IOCompleted } } } } finally { FreePinnedHeaders(pinnedHeaders); } return(statusCode); }
private unsafe List <GCHandle>?SerializeHeaders(bool isOpaqueUpgrade) { Headers.IsReadOnly = true; // Prohibit further modifications. HttpApiTypes.HTTP_UNKNOWN_HEADER[]? unknownHeaders = null; HttpApiTypes.HTTP_RESPONSE_INFO[]? knownHeaderInfo = null; List <GCHandle> pinnedHeaders; GCHandle gcHandle; if (Headers.Count == 0) { return(null); } string headerName; string headerValue; int lookup; byte[]? bytes = null; pinnedHeaders = new List <GCHandle>(); int numUnknownHeaders = 0; int numKnownMultiHeaders = 0; foreach (var headerPair in Headers) { if (headerPair.Value.Count == 0) { continue; } // See if this is an unknown header lookup = HttpApiTypes.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerPair.Key); // Http.Sys doesn't let us send the Connection: Upgrade header as a Known header. if (lookup == -1 || (isOpaqueUpgrade && lookup == (int)HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) { numUnknownHeaders += headerPair.Value.Count; } else if (headerPair.Value.Count > 1) { numKnownMultiHeaders++; } // else known single-value header. } try { fixed(HttpApiTypes.HTTP_KNOWN_HEADER *pKnownHeaders = &_nativeResponse.Response_V1.Headers.KnownHeaders) { foreach (var headerPair in Headers) { if (headerPair.Value.Count == 0) { continue; } headerName = headerPair.Key; StringValues headerValues = headerPair.Value; lookup = HttpApiTypes.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName); // Http.Sys doesn't let us send the Connection: Upgrade header as a Known header. if (lookup == -1 || (isOpaqueUpgrade && lookup == (int)HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection)) { if (unknownHeaders == null) { unknownHeaders = new HttpApiTypes.HTTP_UNKNOWN_HEADER[numUnknownHeaders]; gcHandle = GCHandle.Alloc(unknownHeaders, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); _nativeResponse.Response_V1.Headers.pUnknownHeaders = (HttpApiTypes.HTTP_UNKNOWN_HEADER *)gcHandle.AddrOfPinnedObject(); } for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++) { // Add Name bytes = HeaderEncoding.GetBytes(headerName); unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].NameLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pName = (byte *)gcHandle.AddrOfPinnedObject(); // Add Value headerValue = headerValues[headerValueIndex] ?? string.Empty; bytes = HeaderEncoding.GetBytes(headerValue); unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pRawValue = (byte *)gcHandle.AddrOfPinnedObject(); _nativeResponse.Response_V1.Headers.UnknownHeaderCount++; } } else if (headerPair.Value.Count == 1) { headerValue = headerValues[0] ?? string.Empty; bytes = HeaderEncoding.GetBytes(headerValue); pKnownHeaders[lookup].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); pKnownHeaders[lookup].pRawValue = (byte *)gcHandle.AddrOfPinnedObject(); } else { if (knownHeaderInfo == null) { knownHeaderInfo = new HttpApiTypes.HTTP_RESPONSE_INFO[numKnownMultiHeaders]; gcHandle = GCHandle.Alloc(knownHeaderInfo, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); _nativeResponse.pResponseInfo = (HttpApiTypes.HTTP_RESPONSE_INFO *)gcHandle.AddrOfPinnedObject(); } knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = HttpApiTypes.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = (uint)Marshal.SizeOf <HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS>(); HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS(); header.HeaderId = (HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum)lookup; header.Flags = HttpApiTypes.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // TODO: The docs say this is for www-auth only. HttpApiTypes.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApiTypes.HTTP_KNOWN_HEADER[headerValues.Count]; gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); header.KnownHeaders = (HttpApiTypes.HTTP_KNOWN_HEADER *)gcHandle.AddrOfPinnedObject(); for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++) { // Add Value headerValue = headerValues[headerValueIndex] ?? string.Empty; bytes = HeaderEncoding.GetBytes(headerValue); nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); nativeHeaderValues[header.KnownHeaderCount].pRawValue = (byte *)gcHandle.AddrOfPinnedObject(); header.KnownHeaderCount++; } // This type is a struct, not an object, so pinning it causes a boxed copy to be created. We can't do that until after all the fields are set. gcHandle = GCHandle.Alloc(header, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); knownHeaderInfo[_nativeResponse.ResponseInfoCount].pInfo = (HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS *)gcHandle.AddrOfPinnedObject(); _nativeResponse.ResponseInfoCount++; } } } } catch { FreePinnedHeaders(pinnedHeaders); throw; } return(pinnedHeaders); }
internal DataParseStatus ParseHeaders(byte[] buffer, int size, ref int unparsed, ref int totalResponseHeadersLength, int maximumResponseHeadersLength) { int headerNameStartOffset = -1; int headerNameEndOffset = -1; int headerValueStartOffset = -1; int headerValueEndOffset = -1; int numberOfLf = -1; int index = unparsed; bool spaceAfterLf; string headerMultiLineValue; string headerName; string headerValue; // we need this because this method is entered multiple times. int localTotalResponseHeadersLength = totalResponseHeadersLength; DataParseStatus parseStatus = DataParseStatus.Invalid; GlobalLog.Enter("WebHeaderCollection::ParseHeaders(): size:" + size.ToString() + ", unparsed:" + unparsed.ToString() + " buffer:[" + Encoding.ASCII.GetString(buffer, unparsed, Math.Min(256, size - unparsed)) + "]"); //GlobalLog.Print("WebHeaderCollection::ParseHeaders(): advancing. index=" + index.ToString() + " current character='" + ((char)buffer[index]).ToString() + "':" + ((int)buffer[index]).ToString() + " next character='" + ((char)buffer[index+1]).ToString() + "':" + ((int)buffer[index+1]).ToString()); //GlobalLog.Print("WebHeaderCollection::ParseHeaders(): headerName:[" + headerName + "], headerValue:[" + headerValue + "], headerMultiLineValue:[" + headerMultiLineValue + "] numberOfLf=" + numberOfLf.ToString() + " index=" + index.ToString()); //GlobalLog.Print("WebHeaderCollection::ParseHeaders(): headerNameStartOffset=" + headerNameStartOffset + " headerNameEndOffset=" + headerNameEndOffset + " headerValueStartOffset=" + headerValueStartOffset + " headerValueEndOffset=" + headerValueEndOffset); // // according to RFC216 a header can have the following syntax: // // message-header = field-name ":" [ field-value ] // field-name = token // field-value = *( field-content | LWS ) // field-content = <the OCTETs making up the field-value and consisting of either *TEXT or combinations of token, separators, and quoted-string> // TEXT = <any OCTET except CTLs, but including LWS> // CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)> // SP = <US-ASCII SP, space (32)> // HT = <US-ASCII HT, horizontal-tab (9)> // CR = <US-ASCII CR, carriage return (13)> // LF = <US-ASCII LF, linefeed (10)> // LWS = [CR LF] 1*( SP | HT ) // CHAR = <any US-ASCII character (octets 0 - 127)> // token = 1*<any CHAR except CTLs or separators> // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT // quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) // qdtext = <any TEXT except <">> // quoted-pair = "\" CHAR // // // At each iteration of the following loop we expect to parse a single HTTP header entirely. // for (;;) { // // trim leading whitespaces (LWS) just for extra robustness, in fact if there are leading white spaces then: // 1) it could be that after the status line we might have spaces. handle this. // 2) this should have been detected to be a multiline header so there'll be no spaces and we'll spend some time here. // headerName = string.Empty; headerValue = string.Empty; spaceAfterLf = false; headerMultiLineValue = null; if (Count == 0) { // // so, restrict this extra trimming only on the first header line // while (index < size && (buffer[index] == ' ' || buffer[index] == '\t')) { index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } } if (index == size) { // // we reached the end of the buffer. ask for more data. // parseStatus = DataParseStatus.NeedMoreData; goto quit; } } // // what we have here is the beginning of a new header // headerNameStartOffset = index; while (index < size && (buffer[index] != ':' && buffer[index] != '\n')) { if (buffer[index] > ' ') { // // if thre's an illegal character we should return DataParseStatus.Invalid // instead we choose to be flexible, try to trim it, but include it in the string // headerNameEndOffset = index; } index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } } if (index == size) { // // we reached the end of the buffer. ask for more data. // parseStatus = DataParseStatus.NeedMoreData; goto quit; } startOfValue: // // skip all [' ','\t',':','\r','\n'] characters until HeaderValue starts // if we didn't find any headers yet, we set numberOfLf to 1 // so that we take the '\n' from the status line into account // numberOfLf = (Count == 0 && headerNameEndOffset < 0) ? 1 : 0; while (index < size && numberOfLf < 2 && (buffer[index] <= ' ' || buffer[index] == ':')) { if (buffer[index] == '\n') { numberOfLf++; spaceAfterLf = index + 1 < size && (buffer[index + 1] == ' ' || buffer[index + 1] == '\t'); } index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } } if (numberOfLf == 2 || (numberOfLf == 1 && !spaceAfterLf)) { // // if we've counted two '\n' we got at the end of the headers even if we're past the end of the buffer // if we've counted one '\n' and the first character after that was a ' ' or a '\t' // no matter if we found a ':' or not, treat this as an empty header name. // goto addHeader; } if (index == size) { // // we reached the end of the buffer. ask for more data. // parseStatus = DataParseStatus.NeedMoreData; goto quit; } headerValueStartOffset = index; while (index < size && buffer[index] != '\n') { if (buffer[index] > ' ') { headerValueEndOffset = index; } index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } } if (index == size) { // // we reached the end of the buffer. ask for more data. // parseStatus = DataParseStatus.NeedMoreData; goto quit; } // // at this point we found either a '\n' or the end of the headers // hence we are at the end of the Header Line. 4 options: // 1) need more data // 2) if we find two '\n' => end of headers // 3) if we find one '\n' and a ' ' or a '\t' => multiline header // 4) if we find one '\n' and a valid char => next header // numberOfLf = 0; while (index < size && numberOfLf < 2 && (buffer[index] == '\r' || buffer[index] == '\n')) { if (buffer[index] == '\n') { numberOfLf++; } index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } } if (index == size && numberOfLf < 2) { // // we reached the end of the buffer but not of the headers. ask for more data. // parseStatus = DataParseStatus.NeedMoreData; goto quit; } addHeader: if (headerValueStartOffset >= 0 && headerValueStartOffset > headerNameEndOffset && headerValueEndOffset >= headerValueStartOffset) { // // Encoding fastest way to build the UNICODE string off the byte[] // headerValue = HeaderEncoding.GetString(buffer, headerValueStartOffset, headerValueEndOffset - headerValueStartOffset + 1); } // // if we got here from the beginning of the for loop, headerMultiLineValue will be null // otherwise it will contain the headerValue constructed for the multiline header // add this line as well to it, separated by a single space // headerMultiLineValue = (headerMultiLineValue == null ? headerValue : headerMultiLineValue + " " + headerValue); if (index < size && numberOfLf == 1 && (buffer[index] == ' ' || buffer[index] == '\t')) { // // since we found only one Lf and the next header line begins with a Lws, // this is the beginning of a multiline header. // parse the next line into headerValue later it will be added to headerMultiLineValue // index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } goto startOfValue; } if (headerNameStartOffset >= 0 && headerNameEndOffset >= headerNameStartOffset) { // // Encoding is the fastest way to build the UNICODE string off the byte[] // headerName = HeaderEncoding.GetString(buffer, headerNameStartOffset, headerNameEndOffset - headerNameStartOffset + 1); } // // now it's finally safe to add the header if we have a name for it // if (headerName.Length > 0) { // // the base clasee will check for pre-existing headerValue and append // it using commas as indicated in the RFC // GlobalLog.Print("WebHeaderCollection::ParseHeaders() calling base.Add() key:[" + headerName + "], value:[" + headerMultiLineValue + "]"); base.Add(headerName, headerMultiLineValue); } // // and update unparsed // totalResponseHeadersLength = localTotalResponseHeadersLength; unparsed = index; if (numberOfLf == 2) { parseStatus = DataParseStatus.Done; goto quit; } } // for (;;) quit: GlobalLog.Leave("WebHeaderCollection::ParseHeaders() returning parseStatus:" + parseStatus.ToString()); return(parseStatus); }
internal static string EncodeHeader(string header, string charset, HeaderEncoding headerEncoding) { Encoding encoding = null; try { encoding = Encoding.GetEncoding(charset); } catch { encoding = Encoding.UTF8; charset = "utf-8"; } string encodedHeader = ""; if (headerEncoding == HeaderEncoding.QuotedPrintable) { string[] lines = SplitToLinesToEncode(header, 68); for (int i = 0; i < lines.Length; i++) { if (HasToEncodeHeader(lines[i])) { string encodedLine = EncodeHeaderQuotedPrintable(lines[i], encoding); encodedLine = "=?" + charset + "?" + EnumUtil.ParseHeaderEncoding(headerEncoding) + "?" + encodedLine + "?="; if (encodedHeader.EndsWith(" ") || encodedHeader.EndsWith("\t")) { encodedHeader += encodedLine; } else { encodedHeader += " " + encodedLine; } } else { if (encodedHeader.EndsWith(" ") || encodedHeader.EndsWith("\t")) { encodedHeader += lines[i]; } else { encodedHeader += " " + lines[i]; } } } } else if (headerEncoding == HeaderEncoding.Binary) { string[] lines = SplitToLinesToEncode(header, 68); for (int i = 0; i < lines.Length; i++) { if (HasToEncodeHeader(lines[i])) { byte[] headerBuffer = encoding.GetBytes(lines[i]); string encodedLine = Convert.ToBase64String(headerBuffer, 0, headerBuffer.Length); encodedLine = "=?" + charset + "?" + EnumUtil.ParseHeaderEncoding(headerEncoding) + "?" + encodedLine + "?="; if (encodedHeader.EndsWith(" ") || encodedHeader.EndsWith("\t")) { encodedHeader += encodedLine; } else { encodedHeader += " " + encodedLine; } } else { if (encodedHeader.EndsWith(" ") || encodedHeader.EndsWith("\t")) { encodedHeader += lines[i]; } else { encodedHeader += " " + lines[i]; } } } } return(encodedHeader); }
internal static string DecodeHeader(string encodedWord, ref HeaderEncoding headerEncoding) { int encodedWordStartIndex = encodedWord.IndexOf("=?"); if (encodedWordStartIndex == -1) { return(encodedWord); } int encodedWordEndIndex = encodedWord.IndexOf("?=", encodedWordStartIndex); if (encodedWordEndIndex == -1) { return(encodedWord); } if (encodedWordEndIndex < encodedWordStartIndex) { return(encodedWord); } //remove SPACE between encoded words encodedWord = encodedWord.Replace("?= =?", "?==?"); encodedWord = encodedWord.Replace("?= =?", "?==?"); encodedWord = encodedWord.Replace("?= =?", "?==?"); encodedWord = encodedWord.Replace("?= =?", "?==?"); encodedWord = encodedWord.Replace("?= =?", "?==?"); encodedWord = encodedWord.Replace("?= =?", "?==?"); encodedWord = encodedWord.Replace("?= =?", "?==?"); encodedWord = encodedWord.Replace("?= =?", "?==?"); while (encodedWord.IndexOf("?==?") > 0) { bool replaced = false; int startIndex = encodedWord.IndexOf("?==?"); int firstQuestionMarkIndex = encodedWord.IndexOf("?", startIndex + 4); if (firstQuestionMarkIndex > startIndex) { int secondQuestionMarkIndex = encodedWord.IndexOf("?", firstQuestionMarkIndex + 1); if (secondQuestionMarkIndex > firstQuestionMarkIndex) { encodedWord = encodedWord.Substring(0, startIndex) + encodedWord.Substring(secondQuestionMarkIndex + 1); replaced = true; } } if (!replaced) { break; } } string decodedHeader = encodedWord.Substring(0, encodedWordStartIndex); while (true) { int firstQuestionMarkIndex = encodedWord.IndexOf("?", encodedWordStartIndex + 2); int secondQuestionMarkIndex = encodedWord.IndexOf("?", firstQuestionMarkIndex + 1); if (firstQuestionMarkIndex > -1 && secondQuestionMarkIndex > -1) { encodedWordEndIndex = encodedWord.IndexOf("?=", secondQuestionMarkIndex + 1); if (encodedWordEndIndex == -1) { encodedWordEndIndex = encodedWord.Length - 2; } String headerCharSet = encodedWord.Substring(encodedWordStartIndex + 2, firstQuestionMarkIndex - encodedWordStartIndex - 2); string encodingMethod = encodedWord.Substring(firstQuestionMarkIndex + 1, 1); string encodedText = null; if (encodedWordEndIndex > -1) { encodedText = encodedWord.Substring(secondQuestionMarkIndex + 1, encodedWordEndIndex - secondQuestionMarkIndex - 1); } else { encodedText = encodedWord.Substring(secondQuestionMarkIndex + 1); } if (encodingMethod == "Q" || encodingMethod == "q") { headerEncoding = HeaderEncoding.QuotedPrintable; Encoding encoding = null; try { encoding = Encoding.GetEncoding(headerCharSet); } catch { encoding = Encoding.UTF8; headerCharSet = "utf-8"; } string decodedWord = DecodeQuotedPrintable(encodedText, encoding); decodedWord = decodedWord.Replace("_", " "); decodedHeader += decodedWord; } else if (encodingMethod == "B" || encodingMethod == "b") { headerEncoding = HeaderEncoding.Binary; Encoding encoding = null; try { encoding = Encoding.GetEncoding(headerCharSet); } catch { encoding = Encoding.UTF8; headerCharSet = "utf-8"; } string decodedWord = DecodeBase64(encodedText, encoding); decodedWord = decodedWord.Replace("_", " "); decodedHeader += decodedWord; } } encodedWordStartIndex = encodedWord.IndexOf("=?", encodedWordEndIndex + 2); if (encodedWordStartIndex == -1) { decodedHeader += encodedWord.Substring(encodedWordEndIndex + 2, encodedWord.Length - encodedWordEndIndex - 2); break; } int lastEncodingWordEndIndex = encodedWordEndIndex; encodedWordEndIndex = encodedWord.IndexOf("?=", encodedWordStartIndex); if (encodedWordEndIndex == -1) { decodedHeader += encodedWord.Substring(lastEncodingWordEndIndex + 2, encodedWordStartIndex - lastEncodingWordEndIndex - 2); break; } else { decodedHeader += encodedWord.Substring(lastEncodingWordEndIndex + 2, encodedWordStartIndex - lastEncodingWordEndIndex - 2); } } return(decodedHeader); }
// From HttpSys, except does not write to response private unsafe List <GCHandle> SerializeHeaders(HttpApiTypes.HTTP_RESPONSE_V2 *pHttpResponse) { HttpResponseHeaders.IsReadOnly = true; HttpApiTypes.HTTP_UNKNOWN_HEADER[] unknownHeaders = null; HttpApiTypes.HTTP_RESPONSE_INFO[] knownHeaderInfo = null; var pinnedHeaders = new List <GCHandle>(); GCHandle gcHandle; if (HttpResponseHeaders.Count == 0) { return(null); } string headerName; string headerValue; int lookup; var numUnknownHeaders = 0; int numKnownMultiHeaders = 0; byte[] bytes = null; foreach (var headerPair in HttpResponseHeaders) { if (headerPair.Value.Count == 0) { continue; } lookup = HttpApiTypes.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerPair.Key); if (lookup == -1) // TODO handle opaque stream upgrade? { numUnknownHeaders++; } else if (headerPair.Value.Count > 1) { numKnownMultiHeaders++; } } try { var pKnownHeaders = &pHttpResponse->Response_V1.Headers.KnownHeaders; foreach (var headerPair in HttpResponseHeaders) { if (headerPair.Value.Count == 0) { continue; } headerName = headerPair.Key; StringValues headerValues = headerPair.Value; lookup = HttpApiTypes.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName); if (lookup == -1) { if (unknownHeaders == null) { unknownHeaders = new HttpApiTypes.HTTP_UNKNOWN_HEADER[numUnknownHeaders]; gcHandle = GCHandle.Alloc(unknownHeaders, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); pHttpResponse->Response_V1.Headers.pUnknownHeaders = (HttpApiTypes.HTTP_UNKNOWN_HEADER *)gcHandle.AddrOfPinnedObject(); pHttpResponse->Response_V1.Headers.UnknownHeaderCount = 0; // to remove the iis header for server=... } for (var headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++) { // Add Name bytes = HeaderEncoding.GetBytes(headerName); unknownHeaders[pHttpResponse->Response_V1.Headers.UnknownHeaderCount].NameLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); unknownHeaders[pHttpResponse->Response_V1.Headers.UnknownHeaderCount].pName = (byte *)gcHandle.AddrOfPinnedObject(); // Add Value headerValue = headerValues[headerValueIndex] ?? string.Empty; bytes = HeaderEncoding.GetBytes(headerValue); unknownHeaders[pHttpResponse->Response_V1.Headers.UnknownHeaderCount].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); unknownHeaders[pHttpResponse->Response_V1.Headers.UnknownHeaderCount].pRawValue = (byte *)gcHandle.AddrOfPinnedObject(); pHttpResponse->Response_V1.Headers.UnknownHeaderCount++; } } else if (headerPair.Value.Count == 1) { headerValue = headerValues[0] ?? string.Empty; bytes = HeaderEncoding.GetBytes(headerValue); pKnownHeaders[lookup].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); pKnownHeaders[lookup].pRawValue = (byte *)gcHandle.AddrOfPinnedObject(); } else { if (knownHeaderInfo == null) { knownHeaderInfo = new HttpApiTypes.HTTP_RESPONSE_INFO[numKnownMultiHeaders]; gcHandle = GCHandle.Alloc(knownHeaderInfo, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); pHttpResponse->pResponseInfo = (HttpApiTypes.HTTP_RESPONSE_INFO *)gcHandle.AddrOfPinnedObject(); } knownHeaderInfo[pHttpResponse->ResponseInfoCount].Type = HttpApiTypes.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; knownHeaderInfo[pHttpResponse->ResponseInfoCount].Length = (uint)Marshal.SizeOf <HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS>(); var header = new HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS(); header.HeaderId = (HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum)lookup; header.Flags = HttpApiTypes.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // TODO: The docs say this is for www-auth only. var nativeHeaderValues = new HttpApiTypes.HTTP_KNOWN_HEADER[headerValues.Count]; gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); header.KnownHeaders = (HttpApiTypes.HTTP_KNOWN_HEADER *)gcHandle.AddrOfPinnedObject(); for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++) { // Add Value headerValue = headerValues[headerValueIndex] ?? string.Empty; bytes = HeaderEncoding.GetBytes(headerValue); nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length; gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); nativeHeaderValues[header.KnownHeaderCount].pRawValue = (byte *)gcHandle.AddrOfPinnedObject(); header.KnownHeaderCount++; } // This type is a struct, not an object, so pinning it causes a boxed copy to be created. We can't do that until after all the fields are set. gcHandle = GCHandle.Alloc(header, GCHandleType.Pinned); pinnedHeaders.Add(gcHandle); knownHeaderInfo[pHttpResponse->ResponseInfoCount].pInfo = (HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS *)gcHandle.AddrOfPinnedObject(); pHttpResponse->ResponseInfoCount++; } } } catch (Exception) { FreePinnedHeaders(pinnedHeaders); throw; } return(pinnedHeaders); }
private static IDictionary<string, IHeaderFieldParser> CreateHeaderFieldList() { // NOTE: Header fields not mentioned here are treated as unstructured fieldMap = new Dictionary<string, IHeaderFieldParser>(); fieldMap["content-return"] = new HeaderX400ContentReturn(); fieldMap["x400-content-return"] = new HeaderX400ContentReturn(); fieldMap["delivery-date"] = new HeaderDeliveryDate(); fieldMap["priority"] = new HeaderPriority(); fieldMap["importance"] = new HeaderImportance(); fieldMap["sensitivity"] = new HeaderSensitivity(); fieldMap["reply-by"] = new HeaderDate(); fieldMap["x400-content-identifier"] = new HeaderX400ContentIdentifier(); fieldMap["x400-received"] = new HeaderX400Received(); fieldMap["x400-mts-identifier"] = new HeaderX400MtsIdentifier(); fieldMap["x400-trace"] = new HeaderX400Received(); fieldMap["x400-originator"] = new HeaderX400Originator(); fieldMap["x400-recipients"] = new HeaderX400Recipients(); fieldMap["conversion"] = new HeaderConversion(); fieldMap["conversion-with-loss"] = new HeaderConversionWithLoss(); fieldMap["supersedes"] = new HeaderSupersedes(); fieldMap["expires"] = new HeaderDate(); fieldMap["autoforwarded"] = new HeaderAutoforwarded(); fieldMap["generate-delivery-report"] = new HeaderGenerateDeliveryReport(); fieldMap["incomplete-copy"] = new HeaderIncompleteCopy(); fieldMap["prevent-nondelivery-report"] = new HeaderPreventNondeliveryReport(); fieldMap["alternate-recipient"] = new HeaderAlternateRecipient(); fieldMap["disclose-recipients"] = new HeaderDiscloseRecipients(); fieldMap["expanded-date"] = new HeaderExpandedDate(); fieldMap["newsgroups"] = new HeaderNewsgroups(); fieldMap["path"] = new HeaderPath(); fieldMap["archive"] = new HeaderArchive(); fieldMap["control"] = new HeaderControl(); fieldMap["distribution"] = new HeaderDistribution(); fieldMap["followup-to"] = new HeaderFollowupTo(); fieldMap["injection-date"] = new HeaderInjectionDate(); fieldMap["injection-info"] = new HeaderInjectionInfo(); fieldMap["user-agent"] = new HeaderUserAgent(); fieldMap["xref"] = new HeaderXref(); fieldMap["nntp-posting-date"] = new HeaderInjectionDate(); fieldMap["nntp-posting-host"] = new HeaderNntpPostingHost(); fieldMap["accept-language"] = new HeaderAcceptLanguage(); fieldMap["archived-at"] = new HeaderArchivedAt(); fieldMap["authentication-results"] = new HeaderAuthenticationResults(); fieldMap["auto-submitted"] = new HeaderAutoSubmitted(); fieldMap["base"] = new HeaderContentBase(); fieldMap["bcc"] = new HeaderBcc(); fieldMap["cc"] = new HeaderTo(); fieldMap["content-base"] = new HeaderContentBase(); fieldMap["content-disposition"] = new HeaderContentDisposition(); fieldMap["content-duration"] = new HeaderContentDuration(); fieldMap["content-id"] = new HeaderContentId(); fieldMap["content-language"] = new HeaderContentLanguage(); fieldMap["content-location"] = new HeaderContentLocation(); fieldMap["content-md5"] = new HeaderContentMd5(); fieldMap["content-transfer-encoding"] = new HeaderContentTransferEncoding(); fieldMap["content-type"] = new HeaderContentType(); fieldMap["date"] = new HeaderDate(); fieldMap["deferred-delivery"] = new HeaderDeferredDelivery(); fieldMap["disposition-notification-options"] = new HeaderDispositionNotificationOptions(); fieldMap["disposition-notification-to"] = new HeaderDispositionNotificationTo(); fieldMap["mmhs-authorizing-users"] = new HeaderMmhsAuthorizingUsers(); fieldMap["dkim-signature"] = new HeaderDkimSignature(); fieldMap["ediint-features"] = new HeaderEdiintFeatures(); fieldMap["eesst-version"] = new HeaderEesstVersion(); fieldMap["encoding"] = new HeaderEncoding(); fieldMap["encrypted"] = new HeaderEncrypted(); fieldMap["expiry-date"] = new HeaderDate(); fieldMap["from"] = new HeaderFrom(); fieldMap["in-reply-to"] = new HeaderInReplyTo(); fieldMap["jabber-id"] = new HeaderJabberId(); fieldMap["keywords"] = new HeaderKeywords(); fieldMap["language"] = new HeaderLanguage(); fieldMap["latest-delivery-time"] = new HeaderLatestDeliveryTime(); fieldMap["list-id"] = new HeaderListId(); fieldMap["message-context"] = new HeaderMessageContext(); fieldMap["message-id"] = new HeaderMessageId(); fieldMap["mime-version"] = new HeaderMimeVersion(); fieldMap["mmhs-acp127-message-identifier"] = new HeaderMmhsAcp127MessageIdentifier(); fieldMap["mmhs-codress-message-indicator"] = new HeaderMmhsCodressMessageIndicator(); fieldMap["mmhs-copy-precedence"] = new HeaderMmhsCopyPrecedence(); fieldMap["mmhs-exempted-address"] = new HeaderMmhsExemptedAddress(); fieldMap["mmhs-extended-authorisation-info"] = new HeaderMmhsExtendedAuthorisationInfo(); fieldMap["mmhs-handling-instructions"] = new HeaderMmhsHandlingInstructions(); fieldMap["mmhs-message-instructions"] = new HeaderMmhsMessageInstructions(); fieldMap["mmhs-message-type"] = new HeaderMmhsMessageType(); fieldMap["mmhs-originator-plad"] = new HeaderMmhsOriginatorPlad(); fieldMap["mmhs-originator-reference"] = new HeaderMmhsOriginatorReference(); fieldMap["mmhs-other-recipients-indicator-cc"] = new HeaderMmhsOtherRecipientsIndicatorCc(); fieldMap["mmhs-other-recipients-indicator-to"] = new HeaderMmhsOtherRecipientsIndicatorTo(); fieldMap["mmhs-primary-precedence"] = new HeaderMmhsPrimaryPrecedence(); fieldMap["mmhs-subject-indicator-codes"] = new HeaderMmhsSubjectIndicatorCodes(); fieldMap["mt-priority"] = new HeaderMtPriority(); fieldMap["obsoletes"] = new HeaderObsoletes(); fieldMap["original-from"] = new HeaderFrom(); fieldMap["original-message-id"] = new HeaderMessageId(); fieldMap["original-recipient"] = new HeaderOriginalRecipient(); fieldMap["received"] = new HeaderReceived(); fieldMap["received-spf"] = new HeaderReceivedSpf(); fieldMap["references"] = new HeaderInReplyTo(); fieldMap["reply-to"] = new HeaderResentTo(); fieldMap["require-recipient-valid-since"] = new HeaderRequireRecipientValidSince(); fieldMap["resent-bcc"] = new HeaderBcc(); fieldMap["resent-cc"] = new HeaderResentTo(); fieldMap["resent-date"] = new HeaderDate(); fieldMap["resent-from"] = new HeaderFrom(); fieldMap["resent-message-id"] = new HeaderMessageId(); fieldMap["resent-reply-to"] = new HeaderResentTo(); fieldMap["resent-sender"] = new HeaderSender(); fieldMap["resent-to"] = new HeaderResentTo(); fieldMap["return-path"] = new HeaderReturnPath(); fieldMap["sender"] = new HeaderSender(); fieldMap["sio-label"] = new HeaderSioLabel(); fieldMap["sio-label-history"] = new HeaderSioLabel(); fieldMap["solicitation"] = new HeaderSolicitation(); fieldMap["to"] = new HeaderTo(); fieldMap["vbr-info"] = new HeaderVbrInfo(); fieldMap["x-archived-at"] = new HeaderXArchivedAt(); fieldMap["x-mittente"] = new HeaderSender(); fieldMap["x-ricevuta"] = new HeaderXRicevuta(); fieldMap["x-riferimento-message-id"] = new HeaderMessageId(); fieldMap["x-tiporicevuta"] = new HeaderXTiporicevuta(); fieldMap["x-trasporto"] = new HeaderXTrasporto(); fieldMap["x-verificasicurezza"] = new HeaderXVerificasicurezza(); return fieldMap; }