mirror of
https://github.com/opensim/opensim.git
synced 2026-08-01 06:06:06 +08:00
http server: change uri query handling
This commit is contained in:
@@ -314,7 +314,13 @@ namespace OSHttpServer
|
||||
if (m_stream != null)
|
||||
{
|
||||
if (error == SocketError.Success)
|
||||
m_stream.Flush(); // we should be on a work task
|
||||
{
|
||||
try
|
||||
{
|
||||
m_stream.Flush(); // we should be on a work task so hold on it
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
m_stream.Close();
|
||||
m_stream = null;
|
||||
}
|
||||
@@ -344,7 +350,7 @@ namespace OSHttpServer
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
Disconnect(SocketError.ConnectionReset);
|
||||
Disconnect(SocketError.Success);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -394,7 +400,8 @@ namespace OSHttpServer
|
||||
{
|
||||
LogWriter.Write(this, LogPrio.Fatal, "Failed to reply to a bad request. " + err2);
|
||||
}
|
||||
Disconnect(SocketError.NoRecovery);
|
||||
//Disconnect(SocketError.NoRecovery);
|
||||
Disconnect(SocketError.Success); // try to flush
|
||||
}
|
||||
catch (IOException err)
|
||||
{
|
||||
@@ -434,6 +441,21 @@ namespace OSHttpServer
|
||||
if(--m_maxRequests == 0)
|
||||
m_currentRequest.Connection = ConnectionType.Close;
|
||||
|
||||
if(m_currentRequest.Uri == null)
|
||||
{
|
||||
// should not happen
|
||||
try
|
||||
{
|
||||
Uri uri = new Uri(m_currentRequest.Secure ? "https://" : "http://" + m_currentRequest.UriPath);
|
||||
m_currentRequest.Uri = uri;
|
||||
m_currentRequest.UriPath = uri.AbsolutePath;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// load cookies if they exist
|
||||
if(m_currentRequest.Headers["cookie"] != null)
|
||||
m_currentRequest.SetCookies(new RequestCookies(m_currentRequest.Headers["cookie"]));
|
||||
|
||||
@@ -86,7 +86,6 @@ namespace OSHttpServer
|
||||
return;
|
||||
|
||||
m_activeContexts.TryRemove(imp.contextID, out HttpClientContext dummy);
|
||||
|
||||
imp.Close();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
|
||||
namespace OSHttpServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic helper functions for HTTP
|
||||
/// </summary>
|
||||
public static class HttpHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty URI
|
||||
/// </summary>
|
||||
public static readonly Uri EmptyUri = new Uri("http://localhost/");
|
||||
|
||||
/// <summary>
|
||||
/// Parses a query string.
|
||||
/// </summary>
|
||||
/// <param name="queryString">Query string (URI encoded)</param>
|
||||
/// <returns>A <see cref="HttpInput"/> object if successful; otherwise <see cref="HttpInput.Empty"/></returns>
|
||||
/// <exception cref="ArgumentNullException"><c>queryString</c> is null.</exception>
|
||||
/// <exception cref="FormatException">If string cannot be parsed.</exception>
|
||||
public static HttpInput ParseQueryString(string queryString)
|
||||
{
|
||||
if (queryString == null)
|
||||
throw new ArgumentNullException("queryString");
|
||||
if (queryString == string.Empty)
|
||||
return HttpInput.Empty;
|
||||
|
||||
HttpInput input = new HttpInput("QueryString");
|
||||
|
||||
queryString = queryString.TrimStart('?', '&');
|
||||
|
||||
// a simple value.
|
||||
if (queryString.IndexOf("&") == -1 && !queryString.Contains("%3d") && !queryString.Contains("%3D") && !queryString.Contains("="))
|
||||
{
|
||||
input.Add(string.Empty, queryString);
|
||||
return input;
|
||||
}
|
||||
|
||||
int state = 0;
|
||||
int startpos = 0;
|
||||
string name = null;
|
||||
for (int i = 0; i < queryString.Length; ++i)
|
||||
{
|
||||
int newIndexPos;
|
||||
if (state == 0 && IsEqual(queryString, ref i, out newIndexPos))
|
||||
{
|
||||
name = queryString.Substring(startpos, i - startpos);
|
||||
i = newIndexPos;
|
||||
startpos = i + 1;
|
||||
++state;
|
||||
}
|
||||
else if (state == 1 && IsAmp(queryString, ref i, out newIndexPos))
|
||||
{
|
||||
Add(input, name, queryString.Substring(startpos, i - startpos));
|
||||
i = newIndexPos;
|
||||
startpos = i + 1;
|
||||
state = 0;
|
||||
name = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == 0 && !input.GetEnumerator().MoveNext())
|
||||
throw new FormatException("Not a valid query string: " + queryString);
|
||||
|
||||
if (startpos <= queryString.Length)
|
||||
{
|
||||
if (name != null)
|
||||
Add(input, name, queryString.Substring(startpos, queryString.Length - startpos));
|
||||
else
|
||||
Add(input, string.Empty, queryString.Substring(startpos, queryString.Length - startpos));
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private static bool IsEqual(string queryStr, ref int index, out int outIndex)
|
||||
{
|
||||
outIndex = index;
|
||||
if (queryStr[index] == '=')
|
||||
return true;
|
||||
if (queryStr[index] == '%' && queryStr.Length > index + 2 && queryStr[index + 1] == '3'
|
||||
&& (queryStr[index + 2] == 'd' || queryStr[index + 2] == 'D'))
|
||||
{
|
||||
outIndex += 2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsAmp(string queryStr, ref int index, out int outIndex)
|
||||
{
|
||||
outIndex = index;
|
||||
if (queryStr[index] == '%' && queryStr.Length > index + 2 && queryStr[index + 1] == '2' &&
|
||||
queryStr[index + 2] == '6')
|
||||
outIndex += 2;
|
||||
else if (queryStr[index] == '&')
|
||||
{
|
||||
if (queryStr.Length > index + 4
|
||||
&& (queryStr[index + 1] == 'a' || queryStr[index + 1] == 'A')
|
||||
&& (queryStr[index + 2] == 'm' || queryStr[index + 2] == 'M')
|
||||
&& (queryStr[index + 3] == 'p' || queryStr[index + 3] == 'P')
|
||||
&& queryStr[index + 4] == ';')
|
||||
outIndex += 4;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void Add(IHttpInput input, string name, string value)
|
||||
{
|
||||
input.Add(HttpUtility.UrlDecode(name), HttpUtility.UrlDecode(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using OSHttpServer.Exceptions;
|
||||
|
||||
|
||||
@@ -26,8 +27,8 @@ namespace OSHttpServer
|
||||
private int m_contentLength;
|
||||
private string m_httpVersion = string.Empty;
|
||||
private string m_method = string.Empty;
|
||||
private HttpInput m_queryString = HttpInput.Empty;
|
||||
private Uri m_uri = HttpHelper.EmptyUri;
|
||||
private NameValueCollection m_queryString = null;
|
||||
private Uri m_uri = null;
|
||||
private string m_uriPath;
|
||||
public readonly IHttpClientContext m_context;
|
||||
|
||||
@@ -42,7 +43,7 @@ namespace OSHttpServer
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="HttpRequest"/> is secure.
|
||||
/// </summary>
|
||||
public bool Secure { get; internal set; }
|
||||
public bool Secure { get { return m_context.IsSecured; } }
|
||||
|
||||
public IHttpClientContext Context { get { return m_context; } }
|
||||
/// <summary>
|
||||
@@ -52,24 +53,7 @@ namespace OSHttpServer
|
||||
public string UriPath
|
||||
{
|
||||
get { return m_uriPath; }
|
||||
set
|
||||
{
|
||||
m_uriPath = value;
|
||||
int pos = m_uriPath.IndexOf('?');
|
||||
if (pos != -1)
|
||||
{
|
||||
m_queryString = HttpHelper.ParseQueryString(m_uriPath.Substring(pos + 1));
|
||||
m_param.SetQueryString(m_queryString);
|
||||
string path = m_uriPath.Substring(0, pos);
|
||||
m_uriPath = System.Web.HttpUtility.UrlDecode(path) + "?" + m_uriPath.Substring(pos + 1);
|
||||
UriParts = value.Substring(0, pos).Split(UriSplitters, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uriPath = System.Web.HttpUtility.UrlDecode(m_uriPath);
|
||||
UriParts = value.Split(UriSplitters, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
}
|
||||
set { m_uriPath = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -85,14 +69,6 @@ namespace OSHttpServer
|
||||
|
||||
#region IHttpRequest Members
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the body is complete.
|
||||
/// </summary>
|
||||
public bool BodyIsComplete
|
||||
{
|
||||
get { return m_bodyBytesLeft == 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets kind of types accepted by the client.
|
||||
/// </summary>
|
||||
@@ -167,40 +143,38 @@ namespace OSHttpServer
|
||||
/// <summary>
|
||||
/// Gets variables sent in the query string
|
||||
/// </summary>
|
||||
public HttpInput QueryString
|
||||
public NameValueCollection QueryString
|
||||
{
|
||||
get { return m_queryString; }
|
||||
get
|
||||
{
|
||||
if(m_queryString == null)
|
||||
{
|
||||
if(m_uri == null || m_uri.Query.Length == 0)
|
||||
m_queryString = new NameValueCollection();
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
m_queryString = HttpUtility.ParseQueryString(m_uri.Query);
|
||||
}
|
||||
catch { m_queryString = new NameValueCollection(); }
|
||||
}
|
||||
}
|
||||
|
||||
return m_queryString;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static readonly Uri EmptyUri = new Uri("http://localhost/");
|
||||
/// <summary>
|
||||
/// Gets or sets requested URI.
|
||||
/// </summary>
|
||||
public Uri Uri
|
||||
{
|
||||
get { return m_uri; }
|
||||
set
|
||||
{
|
||||
m_uri = value ?? HttpHelper.EmptyUri;
|
||||
UriParts = m_uri.AbsolutePath.Split(UriSplitters, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
set { m_uri = value ?? EmptyUri; } // not safe
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uri absolute path splitted into parts.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// // uri is: http://gauffin.com/code/tiny/
|
||||
/// Console.WriteLine(request.UriParts[0]); // result: code
|
||||
/// Console.WriteLine(request.UriParts[1]); // result: tiny
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// If you're using controllers than the first part is controller name,
|
||||
/// the second part is method name and the third part is Id property.
|
||||
/// </remarks>
|
||||
/// <seealso cref="Uri"/>
|
||||
public string[] UriParts { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets parameter from <see cref="QueryString"/> or <see cref="Form"/>.
|
||||
/// </summary>
|
||||
@@ -341,7 +315,7 @@ namespace OSHttpServer
|
||||
try
|
||||
{
|
||||
m_uri = new Uri(Secure ? "https://" : "http://" + value + m_uriPath);
|
||||
UriParts = m_uri.AbsolutePath.Split(UriSplitters, StringSplitOptions.RemoveEmptyEntries);
|
||||
m_uriPath = m_uri.AbsolutePath;
|
||||
}
|
||||
catch (UriFormatException err)
|
||||
{
|
||||
@@ -421,8 +395,8 @@ namespace OSHttpServer
|
||||
m_body = null;
|
||||
m_contentLength = 0;
|
||||
m_method = string.Empty;
|
||||
m_uri = HttpHelper.EmptyUri;
|
||||
m_queryString = HttpInput.Empty;
|
||||
m_uri = null;
|
||||
m_queryString = null;
|
||||
m_bodyBytesLeft = 0;
|
||||
m_headers.Clear();
|
||||
m_connection = ConnectionType.KeepAlive;
|
||||
|
||||
@@ -123,12 +123,15 @@ namespace OSHttpServer.Parser
|
||||
string path = value.Substring(oldPos, pos - oldPos);
|
||||
if (path.Length > 4196)
|
||||
throw new BadRequestException("Too long URI.");
|
||||
if (path == "*")
|
||||
throw new BadRequestException("Not supported URI.");
|
||||
|
||||
if (pos + 1 >= value.Length)
|
||||
{
|
||||
m_log.Write(this, LogPrio.Warning, "Invalid request line, missing HTTP-Version. Line: " + value);
|
||||
throw new BadRequestException("Invalid request line, missing HTTP-Version. Line: " + value);
|
||||
}
|
||||
|
||||
string version = value.Substring(pos + 1);
|
||||
if (version.Length < 4 || string.Compare(version.Substring(0, 4), "HTTP", true) != 0)
|
||||
{
|
||||
|
||||
@@ -21,11 +21,6 @@ namespace OSHttpServer
|
||||
/// </summary>
|
||||
Stream Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the body is complete.
|
||||
/// </summary>
|
||||
bool BodyIsComplete { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets kind of connection used for the session.
|
||||
/// </summary>
|
||||
@@ -84,28 +79,13 @@ namespace OSHttpServer
|
||||
/// <summary>
|
||||
/// Gets variables sent in the query string
|
||||
/// </summary>
|
||||
HttpInput QueryString { get; }
|
||||
NameValueCollection QueryString { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets requested URI.
|
||||
/// </summary>
|
||||
Uri Uri { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets URI absolute path divided into parts.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// // URI is: http://gauffin.com/code/tiny/
|
||||
/// Console.WriteLine(request.UriParts[0]); // result: code
|
||||
/// Console.WriteLine(request.UriParts[1]); // result: tiny
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// If you're using controllers than the first part is controller name,
|
||||
/// the second part is method name and the third part is Id property.
|
||||
/// </remarks>
|
||||
/// <seealso cref="Uri"/>
|
||||
string[] UriParts { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets path and query.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user