/// <summary> /// Accepts the callback from client, also handles parsing the /// request, and sending response. /// </summary> public static void AcceptCallback(IAsyncResult ar) { // Connection has been made, let's let the main thread continue ConnectionStatus.AllowListening(); int t = Environment.TickCount; // Get the socket that handles the client request. Socket listener = (Socket)ar.AsyncState; Socket handler = listener.EndAccept(ar); // Buffer for receiving data byte[] buffer = new byte[bufferSize]; // Raw request StringBuilder rawRequest = new StringBuilder(); // Fetching data from server int receivedCount = 0; int requestSize = 0; while (true) { receivedCount = handler.Receive( buffer, 0, bufferSize, SocketFlags.None); requestSize += receivedCount; if (requestSize > maximumRequestSize) { // Exceeded maxiumum request size // TODO: Send a page to client saying that the // request buffer is too large. // For now, just clearing some variables rawRequest.Clear(); buffer = null; // Just logging the failed request (IK!! IK!! It's very f*****g long) Console.WriteLine("New request from {0}, but the request was too large.", (cloudflareMode ? string.Format("(CFIP){0}", (handler.RemoteEndPoint as IPEndPoint).ToString()) : (handler.RemoteEndPoint as IPEndPoint).ToString())); return; } else { rawRequest.Append(Encoding.ASCII.GetString(buffer)); // Checking if this is the end of the receive // buffer. if (receivedCount < bufferSize) { break; } } } // Getting end point IPEndPoint ipep = (handler.RemoteEndPoint as IPEndPoint); // Storing request/response in variables for ease access WebRequestHandler request = default(WebRequestHandler); WebResponseHandler response = default(WebResponseHandler); try { // Generating a request request = WebRequestHandler.ParseRequest( rawRequest.ToString(), ipep.Address, ipep.Port); // Generating a response response = new WebResponseHandler(request.path, ref request); // Getting a string builder for the response StringBuilder responseData = new StringBuilder(); // Appending main header (not sure if it has a name or what) responseData.Append(string.Format("{0} {1} {2}\r\n", request.protocolVersion, response.StatusCode.ToString(), response.StatusCodeDescriptor)); // CGI status (Non-standard) responseData.Append(string.Format("Status: {0} {1}", response.StatusCode, response.StatusCodeDescriptor)); // Appending default headers foreach (HttpHeader header in defaultHeaders) { responseData.Append(string.Format("{0}: {1}\r\n", header.name, header.value)); } // Appending essential headers responseData.Append(string.Format("Date: {0}\r\n", Misc.GetFormattedDate(Misc.time))); // Adding all headers foreach (HttpHeader header in response.Headers) { string value = header.value; // If the value contains a new line, you could // potentially inject extra headers, which is not good. if (value.Contains('\r') || value.Contains('\n') || header.name.Contains('\r') || header.name.Contains('\n')) { return; } // Writing header to buffer responseData.Append(string.Format("{0}: {1}\r\n", header.name, value)); } // If the content isn't empty, add the required headers if (!string.IsNullOrEmpty(response.Content)) { // TODO: Check if content-length is already set. responseData.Append(string.Format("Content-Length: {0}\r\n", response.Content.Length.ToString())); responseData.Append("\r\n"); responseData.Append(response.Content); } // Getting a string to send, we need a reference string rawSend = responseData.ToString(); // Sending the response. Send(ref handler, ref rawSend); // nullifying variables response.Clear(); rawRequest.Clear(); responseData.Clear(); buffer = null; rawSend = null; request = null; response = null; Console.WriteLine(Environment.TickCount - t); // Collect all this shit, don't want to wait for it // to collect them. GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true); } catch (Exception ex) { Logs.LogException(ex.ToString()); } }