/// <summary> /// The constructor of this class. You dont have to use this by your own, NoIIS will handle this for you. /// </summary> /// <param name="request">The client's request.</param> /// <param name="response">Your response to the client's request.</param> public NoIISContext(NoIISRequest request, NoIISResponse response) { this.request = request; this.response = response; }
private static async void clientThread(HttpListener listener) { try { // Will wait for the next client request: var context = await listener.GetContextAsync(); // Filter-out any requests which are to huge: if (context.Request.ContentLength64 > NoIISServer.maxRequestSizeBytes) { Console.WriteLine("A request was to huge: {0} bytes.", context.Request.ContentLength64); context.Response.Abort(); return; } // Read the client's address: var clientAddress = context.Request.RemoteEndPoint.Address.ToString(); // Is this address known? if (!NoIISServer.clients.ContainsKey(clientAddress)) { // Unknown: NoIISServer.createAndStoreClientProfile(clientAddress); } // // In the meanwhile the maintenance thread could take action. Scenario: This client is known // but was not visiting for the allowed time span. One moment after the previous check, the // allowed time span expires and the maintenance thread deletes the entry. In such a case, // an exception will be throwed. Is this the case, we add a new client profile. This is // fine and a valid case. // Client clientProfile; try { // Read the client's profile: clientProfile = NoIISServer.clients[clientAddress]; } catch (KeyNotFoundException) { // Valide case. Create a new entry: NoIISServer.createAndStoreClientProfile(clientAddress); // Read it again. It is not possible that the case occurs again: clientProfile = NoIISServer.clients[clientAddress]; } // Is this client blocked? if (clientProfile.Blocked) { Console.WriteLine("A blocked client tried to access: {0}.", clientAddress); context.Response.Abort(); return; } // File this visit. It is intended to do so after the block check. // Otherwise, an attacker could use this fact to flood the memory // with visits: NoIISServer.clientVisits[clientAddress].Enqueue(DateTime.UtcNow); clientProfile.LastVisitUTC = DateTime.UtcNow; // Store the changed time. This could happens parallel with several // threads. Thus, it is not atomic. This behaviour is intended! Only // the roughly time is necessary. NoIISServer.clients[clientAddress] = clientProfile; try { // Create the NoIIS request: var request = new NoIISRequest(context, NoIISServer.tempFolder); // Create the NoIIS response: var response = new NoIISResponse(context); // Create the NoIIS context with request and response: var webContext = new NoIISContext(request, response); // Search for a handler inside all factories which matches the request: var foundHandler = false; foreach (var factory in NoIISServer.factories) { // Does this factory is able to deliver a handler for this request? var handler = factory.GetHandler(webContext, request.RequestType, request.Path, string.Empty); // Case: Yes, we have found the first handler: if (handler != null) { // Let the handler process the request: handler.ProcessRequest(webContext); foundHandler = true; // We only use the first matching handler: break; } } // Case: No handler was found if (!foundHandler) { Console.WriteLine("No handler found for the URL '{0}'.", request.RawUrl); response.StatusCode = 404; } try { response.Dispose(); } catch { } try { request.Dispose(); } catch { } } catch (Exception e) { Console.WriteLine("Exception while processing request: {0}", e.Message); Console.WriteLine(e.StackTrace); try { context.Response.Abort(); } catch { } } } catch (Exception e) { Console.WriteLine("Exception while accepting request: {0}", e.Message); Console.WriteLine(e.StackTrace); } finally { NoIISServer.semaphoreClients.Release(); } }