// ProxyHTTP: proxy a HTTP request private void ProxyHTTP(Socket client) { NetworkStream netStream = new NetworkStream(client); HandyNetReader reader = new HandyNetReader(netStream); string line = null; int reqNo; int contentLength = 0; string contentType = ""; Match match; string uri; string meth; Dictionary<string, string> headers = new Dictionary<string, string>(); lock (this) { capsReqCount++; reqNo = capsReqCount; } byte[] byteLine = reader.ReadLine(); if(byteLine==null) { //This dirty hack is part of the LIBOMV-457 workaround //The connecting libomv client being proxied can manage to trigger a null from the ReadLine() //The happens just after the seed request and is not seen again. TODO find this bug in the library. netStream.Close(); client.Close(); return; } if (byteLine != null) line = Encoding.UTF8.GetString(byteLine).Replace("\r", ""); if (line == null) throw new Exception("EOF in client HTTP header"); match = new Regex(@"^(\S+)\s+(\S+)\s+(HTTP/\d\.\d)$").Match(line); if (!match.Success) { OpenMetaverse.Logger.Log("[" + reqNo + "] Bad request!", Helpers.LogLevel.Warning); byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n"); netStream.Write(wr, 0, wr.Length); netStream.Close(); client.Close(); return; } meth = match.Groups[1].Captures[0].ToString(); uri = match.Groups[2].Captures[0].ToString(); OpenMetaverse.Logger.Log(String.Format("[{0}] {1}:{2}", reqNo, meth, uri), Helpers.LogLevel.Debug); // read HTTP header do { // read one line of the header line = Encoding.UTF8.GetString(reader.ReadLine()).Replace("\r", ""); // check for premature EOF if (line == null) throw new Exception("EOF in client HTTP header"); if (line == "") break; match = new Regex(@"^([^:]+):\s*(.*)$").Match(line); if (!match.Success) { OpenMetaverse.Logger.Log(String.Format("[{0}] Bad Header: '{1}'", reqNo, line), Helpers.LogLevel.Warning); byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n"); netStream.Write(wr, 0, wr.Length); netStream.Close(); client.Close(); return; } string key = match.Groups[1].Captures[0].ToString(); string val = match.Groups[2].Captures[0].ToString(); headers[key.ToLower()] = val; } while (line != ""); if (headers.ContainsKey("content-length")) { contentLength = Convert.ToInt32(headers["content-length"]); } if (headers.ContainsKey("content-type")) { contentType = headers["content-type"]; } // read the HTTP body into a buffer byte[] content = new byte[contentLength]; reader.Read(content, 0, contentLength); if (contentLength < 8192) OpenMetaverse.Logger.Log(String.Format("[{0}] request length={1}:\n{2}", reqNo, contentLength, Utils.BytesToString(content)), Helpers.LogLevel.Debug); if (uri == "/") { if (contentType == "application/xml+llsd" || contentType == "application/xml") { ProxyLoginSD(netStream, content); } else { ProxyLogin(netStream, content); } } else if (new Regex(@"^/https?://.*$").Match(uri).Success) { ProxyCaps(netStream, meth, uri.Substring(1), headers, content, reqNo); } else if (new Regex(@"^/https?:/.*$").Match(uri).Success) { //This is a libomv client and the proxy CAPS URI has been munged by the C# URI class //Part of the LIBOMV-457 work around, TODO make this much nicer. uri=uri.Replace(":/","://"); ProxyCaps(netStream, meth, uri.Substring(1), headers, content, reqNo); } else { OpenMetaverse.Logger.Log("404 not found: " + uri, Helpers.LogLevel.Error); byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 404 Not Found\r\nContent-Length: 0\r\n\r\n"); netStream.Write(wr, 0, wr.Length); netStream.Close(); client.Close(); return; } netStream.Close(); client.Close(); }
// ProxyHTTP: proxy a HTTP request private void ProxyHTTP(Socket client) { NetworkStream netStream = new NetworkStream(client); HandyNetReader reader = new HandyNetReader(netStream); string line = null; int reqNo; int contentLength = 0; string contentType = ""; Match match; string uri; string meth; Dictionary<string, string> headers = new Dictionary<string, string>(); lock (this) { capsReqCount++; reqNo = capsReqCount; } byte[] byteLine = reader.ReadLine(); if (byteLine != null) line = Encoding.UTF8.GetString(byteLine).Replace("\r", ""); if (line == null) throw new Exception("EOF in client HTTP header"); match = new Regex(@"^(\S+)\s+(\S+)\s+(HTTP/\d\.\d)$").Match(line); if (!match.Success) { Console.WriteLine("[" + reqNo + "] Bad request!"); byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n"); netStream.Write(wr, 0, wr.Length); netStream.Close(); client.Close(); return; } meth = match.Groups[1].Captures[0].ToString(); uri = match.Groups[2].Captures[0].ToString(); #if DEBUG_CAPS Console.WriteLine("[" + reqNo + "] " + meth + ": " + uri); // FIXME - for debugging only #endif // read HTTP header do { // read one line of the header line = Encoding.UTF8.GetString(reader.ReadLine()).Replace("\r", ""); // check for premature EOF if (line == null) throw new Exception("EOF in client HTTP header"); if (line == "") break; match = new Regex(@"^([^:]+):\s*(.*)$").Match(line); if (!match.Success) { Console.WriteLine("[" + reqNo + "] Bad header: '" + line + "'"); byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n"); netStream.Write(wr, 0, wr.Length); netStream.Close(); client.Close(); return; } string key = match.Groups[1].Captures[0].ToString(); string val = match.Groups[2].Captures[0].ToString(); headers[key.ToLower()] = val; } while (line != ""); if (headers.ContainsKey("content-length")) { contentLength = Convert.ToInt32(headers["content-length"]); } if (headers.ContainsKey("content-type")) { contentType = headers["content-type"]; } // read the HTTP body into a buffer byte[] content = new byte[contentLength]; reader.Read(content, 0, contentLength); #if DEBUG_CAPS if (contentLength < 8192) Console.WriteLine("[" + reqNo + "] request length = " + contentLength + ":\n" + Utils.BytesToString(content) + "\n-------------"); #endif if (uri == "/") { if (contentType == "application/xml+llsd" || contentType == "application/xml") { ProxyLoginSD(netStream, content); } else { ProxyLogin(netStream, content); } } else if (new Regex(@"^/https?://.*$").Match(uri).Success) { ProxyCaps(netStream, meth, uri.Substring(1), headers, content, reqNo); } else { Console.WriteLine("404 not found: " + uri); byte[] wr = Encoding.ASCII.GetBytes("HTTP/1.0 404 Not Found\r\nContent-Length: 0\r\n\r\n"); netStream.Write(wr, 0, wr.Length); netStream.Close(); client.Close(); return; } netStream.Close(); client.Close(); }