parent
15344d8d7a
commit
46a11be2ed
|
|
@ -106,7 +106,7 @@ namespace Microsoft.Net.Http.Server
|
|||
_cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2);
|
||||
}
|
||||
|
||||
UrlPrefix prefix = httpContext.Server.UrlPrefixes[(int)_contextId];
|
||||
UrlPrefix prefix = httpContext.Server.UrlPrefixes.GetPrefix((int)_contextId);
|
||||
string orriginalPath = RequestPath;
|
||||
|
||||
// These paths are both unescaped already.
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return string.Equals(Whole, obj as string, StringComparison.OrdinalIgnoreCase);
|
||||
return string.Equals(Whole, Convert.ToString(obj), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Net.Http.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection or URL prefixes
|
||||
/// </summary>
|
||||
public class UrlPrefixCollection : ICollection<UrlPrefix>
|
||||
{
|
||||
private readonly WebListener _webListener;
|
||||
private readonly IDictionary<int, UrlPrefix> _prefixes = new Dictionary<int, UrlPrefix>(1);
|
||||
private int _nextId = 1;
|
||||
|
||||
internal UrlPrefixCollection(WebListener webListener)
|
||||
{
|
||||
_webListener = webListener;
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return _prefixes.Count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public void Add(string prefix)
|
||||
{
|
||||
Add(UrlPrefix.Create(prefix));
|
||||
}
|
||||
|
||||
public void Add(UrlPrefix item)
|
||||
{
|
||||
var id = _nextId++;
|
||||
if (_webListener.IsListening)
|
||||
{
|
||||
RegisterPrefix(item.Whole, id);
|
||||
}
|
||||
_prefixes.Add(id, item);
|
||||
}
|
||||
|
||||
internal UrlPrefix GetPrefix(int id)
|
||||
{
|
||||
return _prefixes[id];
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (_webListener.IsListening)
|
||||
{
|
||||
UnregisterAllPrefixes();
|
||||
}
|
||||
_prefixes.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(UrlPrefix item)
|
||||
{
|
||||
return _prefixes.Values.Contains(item);
|
||||
}
|
||||
|
||||
public void CopyTo(UrlPrefix[] array, int arrayIndex)
|
||||
{
|
||||
_prefixes.Values.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public bool Remove(string prefix)
|
||||
{
|
||||
return Remove(UrlPrefix.Create(prefix));
|
||||
}
|
||||
|
||||
public bool Remove(UrlPrefix item)
|
||||
{
|
||||
int? id = null;
|
||||
foreach (var pair in _prefixes)
|
||||
{
|
||||
if (pair.Value.Equals(item))
|
||||
{
|
||||
id = pair.Key;
|
||||
if (_webListener.IsListening)
|
||||
{
|
||||
UnregisterPrefix(pair.Value.Whole);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (id.HasValue)
|
||||
{
|
||||
_prefixes.Remove(id.Value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerator<UrlPrefix> GetEnumerator()
|
||||
{
|
||||
return _prefixes.Values.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
internal void RegisterAllPrefixes()
|
||||
{
|
||||
// go through the uri list and register for each one of them
|
||||
foreach (var pair in _prefixes)
|
||||
{
|
||||
// We'll get this index back on each request and use it to look up the prefix to calculate PathBase.
|
||||
RegisterPrefix(pair.Value.Whole, pair.Key);
|
||||
}
|
||||
}
|
||||
|
||||
internal void UnregisterAllPrefixes()
|
||||
{
|
||||
// go through the uri list and unregister for each one of them
|
||||
foreach (var prefix in _prefixes.Values)
|
||||
{
|
||||
// ignore possible failures
|
||||
UnregisterPrefix(prefix.Whole);
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterPrefix(string uriPrefix, int contextId)
|
||||
{
|
||||
uint statusCode = 0;
|
||||
|
||||
statusCode =
|
||||
UnsafeNclNativeMethods.HttpApi.HttpAddUrlToUrlGroup(
|
||||
_webListener.UrlGroupId,
|
||||
uriPrefix,
|
||||
(ulong)contextId,
|
||||
0);
|
||||
|
||||
if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS)
|
||||
{
|
||||
if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
throw new WebListenerException((int)statusCode, String.Format(Resources.Exception_PrefixAlreadyRegistered, uriPrefix));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new WebListenerException((int)statusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool UnregisterPrefix(string uriPrefix)
|
||||
{
|
||||
uint statusCode = 0;
|
||||
|
||||
statusCode =
|
||||
UnsafeNclNativeMethods.HttpApi.HttpRemoveUrlFromUrlGroup(
|
||||
_webListener.UrlGroupId,
|
||||
uriPrefix,
|
||||
0);
|
||||
|
||||
if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
private object _internalLock;
|
||||
|
||||
private List<UrlPrefix> _urlPrefixes = new List<UrlPrefix>();
|
||||
private UrlPrefixCollection _urlPrefixes;
|
||||
|
||||
// The native request queue
|
||||
private long? _requestQueueLength;
|
||||
|
|
@ -103,6 +103,7 @@ namespace Microsoft.Net.Http.Server
|
|||
_state = State.Stopped;
|
||||
_internalLock = new object();
|
||||
|
||||
_urlPrefixes = new UrlPrefixCollection(this);
|
||||
_timeoutManager = new TimeoutManager(this);
|
||||
_authManager = new AuthenticationManager(this);
|
||||
_connectionCancellationTokens = new ConcurrentDictionary<ulong, ConnectionCancellation>();
|
||||
|
|
@ -120,7 +121,7 @@ namespace Microsoft.Net.Http.Server
|
|||
get { return _logger; }
|
||||
}
|
||||
|
||||
public List<UrlPrefix> UrlPrefixes
|
||||
public UrlPrefixCollection UrlPrefixes
|
||||
{
|
||||
get { return _urlPrefixes; }
|
||||
}
|
||||
|
|
@ -133,6 +134,11 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
internal ulong UrlGroupId
|
||||
{
|
||||
get { return _urlGroupId; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exposes the Http.Sys timeout configurations. These may also be configured in the registry.
|
||||
/// </summary>
|
||||
|
|
@ -258,29 +264,6 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
internal void RemoveAll(bool clear)
|
||||
{
|
||||
CheckDisposed();
|
||||
// go through the uri list and unregister for each one of them
|
||||
if (_urlPrefixes.Count > 0)
|
||||
{
|
||||
LogHelper.LogInfo(_logger, "RemoveAll");
|
||||
if (_state == State.Started)
|
||||
{
|
||||
foreach (UrlPrefix registeredPrefix in _urlPrefixes)
|
||||
{
|
||||
// ignore possible failures
|
||||
InternalRemovePrefix(registeredPrefix.Whole);
|
||||
}
|
||||
}
|
||||
|
||||
if (clear)
|
||||
{
|
||||
_urlPrefixes.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IntPtr DangerousGetHandle()
|
||||
{
|
||||
return _requestQueueHandle.DangerousGetHandle();
|
||||
|
|
@ -379,7 +362,7 @@ namespace Microsoft.Net.Http.Server
|
|||
// All resources are set up correctly. Now add all prefixes.
|
||||
try
|
||||
{
|
||||
AddAllPrefixes();
|
||||
_urlPrefixes.RegisterAllPrefixes();
|
||||
}
|
||||
catch (WebListenerException)
|
||||
{
|
||||
|
|
@ -489,7 +472,7 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
LogHelper.LogInfo(_logger, "Stop");
|
||||
|
||||
RemoveAll(false);
|
||||
_urlPrefixes.UnregisterAllPrefixes();
|
||||
|
||||
_state = State.Stopped;
|
||||
|
||||
|
|
@ -586,62 +569,6 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
private uint InternalAddPrefix(string uriPrefix, int contextId)
|
||||
{
|
||||
uint statusCode = 0;
|
||||
|
||||
statusCode =
|
||||
UnsafeNclNativeMethods.HttpApi.HttpAddUrlToUrlGroup(
|
||||
_urlGroupId,
|
||||
uriPrefix,
|
||||
(ulong)contextId,
|
||||
0);
|
||||
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
private bool InternalRemovePrefix(string uriPrefix)
|
||||
{
|
||||
uint statusCode = 0;
|
||||
|
||||
statusCode =
|
||||
UnsafeNclNativeMethods.HttpApi.HttpRemoveUrlFromUrlGroup(
|
||||
_urlGroupId,
|
||||
uriPrefix,
|
||||
0);
|
||||
|
||||
if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void AddAllPrefixes()
|
||||
{
|
||||
// go through the uri list and register for each one of them
|
||||
if (_urlPrefixes.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < _urlPrefixes.Count; i++)
|
||||
{
|
||||
// We'll get this index back on each request and use it to look up the prefix to calculate PathBase.
|
||||
UrlPrefix registeredPrefix = _urlPrefixes[i];
|
||||
uint statusCode = InternalAddPrefix(registeredPrefix.Whole, i);
|
||||
if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS)
|
||||
{
|
||||
if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
throw new WebListenerException((int)statusCode, String.Format(Resources.Exception_PrefixAlreadyRegistered, registeredPrefix.Whole));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new WebListenerException((int)statusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal unsafe bool ValidateRequest(NativeRequestContext requestMemory)
|
||||
{
|
||||
// Block potential DOS attacks
|
||||
|
|
@ -713,7 +640,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
private CancellationToken GetConnectionCancellation(ulong connectionId)
|
||||
{
|
||||
// Read case is performance senstive
|
||||
// Read case is performance sensitive
|
||||
ConnectionCancellation cancellation;
|
||||
if (!_connectionCancellationTokens.TryGetValue(connectionId, out cancellation))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -181,6 +181,69 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Server_HotAddPrefix_Success()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
Assert.Equal(string.Empty, context.Request.PathBase);
|
||||
Assert.Equal("/", context.Request.Path);
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
Assert.Equal(string.Empty, response);
|
||||
|
||||
address += "pathbase/";
|
||||
server.UrlPrefixes.Add(address);
|
||||
|
||||
responseTask = SendRequestAsync(address);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
Assert.Equal("/pathbase", context.Request.PathBase);
|
||||
Assert.Equal("/", context.Request.Path);
|
||||
context.Dispose();
|
||||
|
||||
response = await responseTask;
|
||||
Assert.Equal(string.Empty, response);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Server_HotRemovePrefix_Success()
|
||||
{
|
||||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
address += "pathbase/";
|
||||
server.UrlPrefixes.Add(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
Assert.Equal("/pathbase", context.Request.PathBase);
|
||||
Assert.Equal("/", context.Request.Path);
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
Assert.Equal(string.Empty, response);
|
||||
|
||||
Assert.True(server.UrlPrefixes.Remove(address));
|
||||
|
||||
responseTask = SendRequestAsync(address);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
Assert.Equal(string.Empty, context.Request.PathBase);
|
||||
Assert.Equal("/pathbase/", context.Request.Path);
|
||||
context.Dispose();
|
||||
|
||||
response = await responseTask;
|
||||
Assert.Equal(string.Empty, response);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> SendRequestAsync(string uri)
|
||||
{
|
||||
ServicePointManager.DefaultConnectionLimit = 100;
|
||||
|
|
|
|||
Loading…
Reference in New Issue