private const long MAX_REQUEST_SLIDING_TIMEOUT = 2 * 1000; // 1 seconds public HttpRequest() { _headers = new MFToolkit.Collection.Spezialized.NameValueCollection(); }
internal bool Read(Stream stream, IPEndPoint endPoint) { byte[] buffer = new byte[1024]; RequestParserState state = RequestParserState.ReadMethod; string key = ""; string value = ""; MemoryStream ms = null; DateTime begin = DateTime.Now; DateTime lastByteReceived = begin; if (endPoint != null) UserHostAddress = endPoint.Address.ToString(); while (true) { if (state == RequestParserState.ReadDone) return true; int bytesRead = 0; int idx = 0; #if(MF) // set all bytes to null byte (strings are ending with null byte in MF) Array.Clear(buffer, 0, buffer.Length); #endif try { bytesRead = stream.Read(buffer, 0, buffer.Length); if (bytesRead > 0) lastByteReceived = DateTime.Now; } catch (IOException) { break; } catch (Exception) { DateTime nd = DateTime.Now; #if(MF) if((nd.Ticks - lastByteReceived.Ticks) / TimeSpan.TicksPerMillisecond > MAX_REQUEST_SLIDING_TIMEOUT) break; #else // if ((nd - lastByteReceived).TotalMilliseconds > MAX_REQUEST_SLIDING_TIMEOUT) // break; #endif if (HttpMethod == "POST" && (_body == null || _body.Length < ContentLength)) continue; #if(MF) if((nd.Ticks - begin.Ticks) / TimeSpan.TicksPerMillisecond < MAX_REQUEST_TIMEOUT) continue; #else // if ((nd - begin).TotalMilliseconds < MAX_REQUEST_TIMEOUT) // continue; #endif break; } if (bytesRead == 0) // should never happen break; totalBytes += bytesRead; #if(FILELOG && !MF && !WindowsCE) File.AppendAllText("loghttp-" + socket.RemoteEndPoint.ToString().Replace(":", "-") + ".txt", Encoding.UTF8.GetString(buffer, 0, bytesRead) + "\r\n"); #endif if (totalBytes <= idx) continue; do { switch (state) { case RequestParserState.ReadMethod: if (buffer[idx] != ' ') HttpMethod += (char)buffer[idx++]; else { // TODO: add a allowed methods list //if (HttpMethod != "POST" && HttpMethod != "GET" && HttpMethod != "OPTIONS") // throw new HttpException(HttpStatusCode.MethodNotAllowed); idx++; state = RequestParserState.ReadUrl; } break; case RequestParserState.ReadUrl: if (buffer[idx] == '?') { idx++; key = ""; _params = new MFToolkit.Collection.Spezialized.NameValueCollection(); state = RequestParserState.ReadParamKey; } else if (buffer[idx] != ' ') { RawUrl += (char)buffer[idx++]; } else { idx++; RawUrl = HttpServerUtility.UrlDecode(RawUrl); state = RequestParserState.ReadVersion; } break; case RequestParserState.ReadParamKey: if (buffer[idx] == '=') { idx++; value = ""; state = RequestParserState.ReadParamValue; } else if (buffer[idx] == ' ') { idx++; RawUrl = HttpServerUtility.UrlDecode(RawUrl); state = RequestParserState.ReadVersion; } else { key += (char)buffer[idx++]; } break; case RequestParserState.ReadParamValue: if (buffer[idx] == '&') { idx++; key = HttpServerUtility.UrlDecode(key); value = HttpServerUtility.UrlDecode(value); Params[key] = (Params[key] != null ? Params[key] + ", " + value : value); key = ""; value = ""; state = RequestParserState.ReadParamKey; } else if (buffer[idx] == ' ') { idx++; key = HttpServerUtility.UrlDecode(key); value = HttpServerUtility.UrlDecode(value); Params[key] = (Params[key] != null ? Params[key] + ", " + value : value); RawUrl = HttpServerUtility.UrlDecode(RawUrl); state = RequestParserState.ReadVersion; } else { value += (char)buffer[idx++]; } break; case RequestParserState.ReadVersion: if (buffer[idx] == '\r') idx++; else if (buffer[idx] != '\n') HttpVersion += (char)buffer[idx++]; else { if (HttpVersion != "HTTP/1.1" && HttpVersion != "HTTP/1.0") throw new HttpException(HttpStatusCode.HttpVersionNotSupported); idx++; key = ""; Headers = new MFToolkit.Collection.Spezialized.NameValueCollection(); state = RequestParserState.ReadHeaderKey; } break; case RequestParserState.ReadHeaderKey: if (buffer[idx] == '\r') idx++; else if (buffer[idx] == '\n') { idx++; if (HttpMethod == "POST") state = RequestParserState.ReadBody; else { state = RequestParserState.ReadDone; // well, we don't really need this return true; } } else if (buffer[idx] == ':') idx++; else if (buffer[idx] != ' ') key += (char)buffer[idx++]; else { idx++; value = ""; state = RequestParserState.ReadHeaderValue; } break; case RequestParserState.ReadHeaderValue: if (buffer[idx] == '\r') idx++; else if (buffer[idx] != '\n') value += (char)buffer[idx++]; else { idx++; Headers.Add(key, value); key = ""; state = RequestParserState.ReadHeaderKey; } break; case RequestParserState.ReadBody: if (ContentLength > MAX_CONTENT_LENGTH) { // TODO: how can I stop the client to cancel http request //throw new HttpException(HttpStatusCode.RequestEntitiyTooLarge); } if (ms == null) ms = new MemoryStream(); ms.Write(buffer, idx, bytesRead - idx); idx = bytesRead; if (ms.Length >= ContentLength) { _body = ms.ToArray(); // if using a <form/> tag with POST check if it is urlencoded or multipart boundary if (ContentType.IndexOf("application/x-www-form-urlencoded") != -1) { _form = new MFToolkit.Collection.Spezialized.NameValueCollection(); key = ""; value = null; for (int i = 0; i < _body.Length; i++) { if (_body[i] == '=') value = ""; else if (_body[i] == '&') { _form.Add(key, value != null ? HttpServerUtility.UrlDecode(value) : ""); key = ""; value = null; } else if (value == null) key += (char)_body[i]; else if (value != null) value += (char)_body[i]; } if (key != null && key.Length > 0) { _form.Add(key, value != null ? HttpServerUtility.UrlDecode(value) : ""); } } else if (ContentType != null && ContentType.Length > "multipart/form-data; boundary=".Length && ContentType.Substring(0, "multipart/form-data; boundary=".Length) == "multipart/form-data; boundary=") { string boundary = ContentType.Substring("multipart/form-data; boundary=".Length); _mime = new MimeContentCollection(); MimeParser mp = new MimeParser(_body, boundary); MimeContent mime = mp.GetNextContent(); while (mime != null) { _mime.Add(mime.Name, mime); if (mime.Headers["Content-Disposition"] != null && mime.Headers["Content-Disposition"].IndexOf("form-data") >= 0) { if (_form == null) _form = new MFToolkit.Collection.Spezialized.NameValueCollection(); _form.Add(mime.Name, (mime.Content != null && mime.Content.Length > 0 ? new string(Encoding.UTF8.GetChars(mime.Content)) : "")); } mime = mp.GetNextContent(); } } state = RequestParserState.ReadDone; // well, we don't really need this return true; } break; case RequestParserState.ReadDone: // well, we don't really need this return true; default: //idx++; break; } } while (idx < bytesRead); } return false; }
internal bool Read(Stream stream, IPEndPoint endPoint) { byte[] buffer = new byte[1024]; RequestParserState state = RequestParserState.ReadMethod; string key = ""; string value = ""; MemoryStream ms = null; DateTime begin = DateTime.Now; DateTime lastByteReceived = begin; if (endPoint != null) { UserHostAddress = endPoint.Address.ToString(); } while (true) { if (state == RequestParserState.ReadDone) { return(true); } int bytesRead = 0; int idx = 0; #if (MF) // set all bytes to null byte (strings are ending with null byte in MF) Array.Clear(buffer, 0, buffer.Length); #endif try { bytesRead = stream.Read(buffer, 0, buffer.Length); if (bytesRead > 0) { lastByteReceived = DateTime.Now; } } catch (IOException) { break; } catch (Exception) { DateTime nd = DateTime.Now; #if (MF) if ((nd.Ticks - lastByteReceived.Ticks) / TimeSpan.TicksPerMillisecond > MAX_REQUEST_SLIDING_TIMEOUT) { break; } #else // if ((nd - lastByteReceived).TotalMilliseconds > MAX_REQUEST_SLIDING_TIMEOUT) // break; #endif if (HttpMethod == "POST" && (_body == null || _body.Length < ContentLength)) { continue; } #if (MF) if ((nd.Ticks - begin.Ticks) / TimeSpan.TicksPerMillisecond < MAX_REQUEST_TIMEOUT) { continue; } #else // if ((nd - begin).TotalMilliseconds < MAX_REQUEST_TIMEOUT) // continue; #endif break; } if (bytesRead == 0) // should never happen { break; } totalBytes += bytesRead; #if (FILELOG && !MF && !WindowsCE) File.AppendAllText("loghttp-" + socket.RemoteEndPoint.ToString().Replace(":", "-") + ".txt", Encoding.UTF8.GetString(buffer, 0, bytesRead) + "\r\n"); #endif if (totalBytes <= idx) { continue; } do { switch (state) { case RequestParserState.ReadMethod: if (buffer[idx] != ' ') { HttpMethod += (char)buffer[idx++]; } else { // TODO: add a allowed methods list //if (HttpMethod != "POST" && HttpMethod != "GET" && HttpMethod != "OPTIONS") // throw new HttpException(HttpStatusCode.MethodNotAllowed); idx++; state = RequestParserState.ReadUrl; } break; case RequestParserState.ReadUrl: if (buffer[idx] == '?') { idx++; key = ""; _params = new MFToolkit.Collection.Spezialized.NameValueCollection(); state = RequestParserState.ReadParamKey; } else if (buffer[idx] != ' ') { RawUrl += (char)buffer[idx++]; } else { idx++; RawUrl = HttpServerUtility.UrlDecode(RawUrl); state = RequestParserState.ReadVersion; } break; case RequestParserState.ReadParamKey: if (buffer[idx] == '=') { idx++; value = ""; state = RequestParserState.ReadParamValue; } else if (buffer[idx] == ' ') { idx++; RawUrl = HttpServerUtility.UrlDecode(RawUrl); state = RequestParserState.ReadVersion; } else { key += (char)buffer[idx++]; } break; case RequestParserState.ReadParamValue: if (buffer[idx] == '&') { idx++; key = HttpServerUtility.UrlDecode(key); value = HttpServerUtility.UrlDecode(value); Params[key] = (Params[key] != null ? Params[key] + ", " + value : value); key = ""; value = ""; state = RequestParserState.ReadParamKey; } else if (buffer[idx] == ' ') { idx++; key = HttpServerUtility.UrlDecode(key); value = HttpServerUtility.UrlDecode(value); Params[key] = (Params[key] != null ? Params[key] + ", " + value : value); RawUrl = HttpServerUtility.UrlDecode(RawUrl); state = RequestParserState.ReadVersion; } else { value += (char)buffer[idx++]; } break; case RequestParserState.ReadVersion: if (buffer[idx] == '\r') { idx++; } else if (buffer[idx] != '\n') { HttpVersion += (char)buffer[idx++]; } else { if (HttpVersion != "HTTP/1.1" && HttpVersion != "HTTP/1.0") { throw new HttpException(HttpStatusCode.HttpVersionNotSupported); } idx++; key = ""; Headers = new MFToolkit.Collection.Spezialized.NameValueCollection(); state = RequestParserState.ReadHeaderKey; } break; case RequestParserState.ReadHeaderKey: if (buffer[idx] == '\r') { idx++; } else if (buffer[idx] == '\n') { idx++; if (HttpMethod == "POST") { state = RequestParserState.ReadBody; } else { state = RequestParserState.ReadDone; // well, we don't really need this return(true); } } else if (buffer[idx] == ':') { idx++; } else if (buffer[idx] != ' ') { key += (char)buffer[idx++]; } else { idx++; value = ""; state = RequestParserState.ReadHeaderValue; } break; case RequestParserState.ReadHeaderValue: if (buffer[idx] == '\r') { idx++; } else if (buffer[idx] != '\n') { value += (char)buffer[idx++]; } else { idx++; Headers.Add(key, value); key = ""; state = RequestParserState.ReadHeaderKey; } break; case RequestParserState.ReadBody: if (ContentLength > MAX_CONTENT_LENGTH) { // TODO: how can I stop the client to cancel http request //throw new HttpException(HttpStatusCode.RequestEntitiyTooLarge); } if (ms == null) { ms = new MemoryStream(); } ms.Write(buffer, idx, bytesRead - idx); idx = bytesRead; if (ms.Length >= ContentLength) { _body = ms.ToArray(); // if using a <form/> tag with POST check if it is urlencoded or multipart boundary if (ContentType.IndexOf("application/x-www-form-urlencoded") != -1) { _form = new MFToolkit.Collection.Spezialized.NameValueCollection(); key = ""; value = null; for (int i = 0; i < _body.Length; i++) { if (_body[i] == '=') { value = ""; } else if (_body[i] == '&') { _form.Add(key, value != null ? HttpServerUtility.UrlDecode(value) : ""); key = ""; value = null; } else if (value == null) { key += (char)_body[i]; } else if (value != null) { value += (char)_body[i]; } } if (key != null && key.Length > 0) { _form.Add(key, value != null ? HttpServerUtility.UrlDecode(value) : ""); } } else if (ContentType != null && ContentType.Length > "multipart/form-data; boundary=".Length && ContentType.Substring(0, "multipart/form-data; boundary=".Length) == "multipart/form-data; boundary=") { string boundary = ContentType.Substring("multipart/form-data; boundary=".Length); _mime = new MimeContentCollection(); MimeParser mp = new MimeParser(_body, boundary); MimeContent mime = mp.GetNextContent(); while (mime != null) { _mime.Add(mime.Name, mime); if (mime.Headers["Content-Disposition"] != null && mime.Headers["Content-Disposition"].IndexOf("form-data") >= 0) { if (_form == null) { _form = new MFToolkit.Collection.Spezialized.NameValueCollection(); } _form.Add(mime.Name, (mime.Content != null && mime.Content.Length > 0 ? new string(Encoding.UTF8.GetChars(mime.Content)) : "")); } mime = mp.GetNextContent(); } } state = RequestParserState.ReadDone; // well, we don't really need this return(true); } break; case RequestParserState.ReadDone: // well, we don't really need this return(true); default: //idx++; break; } }while (idx < bytesRead); } return(false); }