static void DoRequest(NetworkStream stream, Socket connection) { try { StreamWriter sw = new StreamWriter(stream); //Writes to stream StreamReader sr = new StreamReader(stream); //Reads from stream ProtocolType type = ProtocolType.WHOIS; //Sets the protocol type to WHOIS by default string temp; //A temporary string variable string name = null; //A string used to hold the first line commonly containing the name List <string> header = new List <string>(); //A list of strings to add each line of optional headers to string location = null; //A string to save the location to bool head = true; //A boolean to say whether the header is being read (true) or not (false) Stopwatch watch = new Stopwatch(); //Stopwatch for debugging. This allows for seeing how long it takes to do a segment of code int count = 1; //~~~~~DEBUGGING~~~~~ if (debugMode) { watch.Start(); //Starts the stopwatch to time the reading of the code //~~~~~DEBUGGING~~~~~ } try //Try and read { while (true) //Loop through until break out { temp = sr.ReadLine(); //Set the temporary variable to the string that is read if (debugMode && name == null) { Console.WriteLine("Received: \n"); Console.WriteLine("Line " + count + ": " + temp); count++; } //~~~~~DEBUGGING~~~~~ else if (debugMode) { Console.WriteLine("Line " + count + ": " + temp); count++; } //~~~~~DEBUGGING~~~~~ if (name == null) //If the first line hasn't been set yet... { name = temp; //... then set it to the temporary line } else if (head && (name.Contains("POST /") && name.Contains(" HTTP/1.0") || name.Contains("POST / HTTP/1.1") || name.Contains("PUT /") || name.Contains("GET /?") && name.Contains(" HTTP/1.0") || name.Contains("GET /?name=") && name.Contains(" HTTP/1.1"))) //Else if the header hasn't been read yet... { try //Try to... { if (string.IsNullOrWhiteSpace(temp)) //... and the temporary string is empty { head = false; //Then we are no longer reading the header } else if (head && name.Contains("PUT /")) //Else if we are reading the header and the first line contains "PUT /"... { location = temp; //... then set the location line to the temporary string break; //Break out of the for loop which means no more reading data } else //Else if the previous IFs aren't met then... { header.Add(temp); //... add the temporary string to the list of header strings } } catch //Catch any errors and... { break; //... break out the reading loop } } else if (head && temp == null) { break; } else //Else if the previous IFs aren't met then... { location = temp; //... then set the location break; //... break out the reading loop } if (!name.Contains("POST /") && !name.Contains("PUT /") && head) //If the name doesn't contain "POST /" and "PUT /" and it's currently reading the header then... { break; //... break out the reading loop } } } catch (IOException) //If it can't read anymore it will catch an IOException { if (name != null) //If it has read some data { Console.WriteLine("\nERROR: Data was read but server/client timed out.\n"); status = "EXCEPTION"; } else //Else if it hasn't read any data { Console.WriteLine("\nERROR: No data was retrieved.\n"); status = "EXCEPTION"; } } if (debugMode) { Console.WriteLine("\n"); watch.Stop(); //Stop the stopwatch Console.WriteLine("Time taken to read: " + watch.ElapsedMilliseconds + "ms"); } //~~~~~DEBUGGING~~~~~ if (string.IsNullOrWhiteSpace(location)) //If the location line is null... { location = string.Join("\n", header); //... then the location line is all of the header lines joined together } if (name.Contains("POST / HTTP/1.1") || name.Contains("GET /?name=") && name.Contains(" HTTP/1.1")) //If the name contains the POST or GET with HTTP/1.1... { type = ProtocolType.HTTP1; //... then the protocol type = HTTP1 if (debugMode) { Console.WriteLine("Protocol: HTTP/1.1"); //~~~~~DEBUGGING~~~~~ } } else if ((name.Contains("GET /?") || name.Contains("POST /")) && name.Contains(" HTTP/1.0")) //Else if the name contains the POST or GET with HTTP/1.0... { type = ProtocolType.HTTP0; //... then the protocol type = HTTP0 if (debugMode) { Console.WriteLine("Protocol: HTTP/1.0"); //~~~~~DEBUGGING~~~~~ } } else if (name.Contains("GET /") || name.Contains("PUT /")) //Else if the name conatins the GET or PUT for the http0.9... { type = ProtocolType.HTTP9; //... then the type = HTTP9 if (debugMode) { Console.WriteLine("Protocol: HTTP/0.9"); //~~~~~DEBUGGING~~~~~ } if (string.IsNullOrWhiteSpace(location) && name.Contains("PUT /")) { type = ProtocolType.WHOIS; if (debugMode) { Console.WriteLine("Protocol: WHOIS"); //~~~~~DEBUGGING~~~~~ } } } else //Else if none of the previous IFs are met... { type = ProtocolType.WHOIS; //... then the type = WHOIS if (debugMode) { Console.WriteLine("Protocol: WHOIS"); //~~~~~DEBUGGING~~~~~ } } switch (type) //Switch on the type to determine what to do for that computer { case ProtocolType.HTTP1: //If the type is HTTP1 then... string[] x = name.Split(new char[] { '=' }, 2); //Split the name string, into a string array, on the = if (x[0].Contains("GET")) //If the first element contians GET.. { string[] a = x[1].Split(new char[] { ' ' }, 2); //Split the second element of x into a string array name = a[0]; //The name string now = the first element of a if (locations.TryGetValue(name, out string value)) //If the database (dictionary) contains name { //Stream write this... sw.WriteLine("HTTP/1.1" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n" + "\r\n" + value); if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine("HTTP/1.1" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n" + "\r\n" + value); } //~~~~~DEBUGGING~~~~~ } else //Otherwise... { //Stream write this... sw.WriteLine("HTTP/1.1" + " " + "404" + " " + "Not" + " " + "Found" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine("HTTP/1.1" + " " + "404" + " " + "Not" + " " + "Found" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); } //~~~~~DEBUGGING~~~~~ status = "UNKOWN"; } line = "GET " + name; } else //Otherwise... { string[] a = location.Split(new char[] { '=' }, 3); //Split the location line by the = string[] b = a[1].Split(new char[] { '&' }, 2); //Split the second element of a by the & name = b[0]; //The name string now = the first element of b location = a[2]; //The location string now = the third element of a if (locations.TryGetValue(name, out string value)) //If the database (dictionary) contains name { locations[name] = location; //The Key's value now = location } else //Otherwise... { locations.Add(name, location); //Add the name and location to the dictionary } //Stream write this... sw.WriteLine("HTTP/1.1" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine("HTTP/1.1" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); } //~~~~~DEBUGGING~~~~~ line = "PUT " + name + " " + location; } break; //Break out of the case case ProtocolType.HTTP0: //If the type is HTTP0 then... string[] y = name.Split(new char[] { ' ' }, 3); //Split the name string by a space if (y[0].Contains("GET")) //If the first element of y contains GET... { string[] a = y[1].Split(new char[] { '?' }, 2); //Split the second element of y on the ? name = a[1]; //The name string now = the second element of a if (locations.TryGetValue(name, out string value)) //If the database (dictionary) contains name { //Stream write this... sw.WriteLine("HTTP/1.0" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n" + "\r\n" + value); if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine("HTTP/1.0" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n" + "\r\n" + value); } //~~~~~DEBUGGING~~~~~ } else //Otherwise... { //Stream write this... sw.WriteLine("HTTP/1.0" + " " + "404" + " " + "Not" + " " + "Found" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine("HTTP/1.0" + " " + "404" + " " + "Not" + " " + "Found" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); } //~~~~~DEBUGGING~~~~~ status = "UNKOWN"; } line = "GET " + name; } else //Otherwise... { string[] a = y[1].Split(new char[] { '/' }, 2); //Split the second element of y on the / name = a[1]; //The name string now = the second element of a if (locations.TryGetValue(name, out string value)) //If the database (dictionary) contains name { locations[name] = location; //The Key's value is now = location } else //Otherwise... { locations.Add(name, location); //Add the name and location to the dictionary } //Stream write this... sw.WriteLine("HTTP/1.0" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine("HTTP/1.0" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); } //~~~~~DEBUGGING~~~~~ line = "PUT " + name + " " + location; } break; //Break out of the case case ProtocolType.HTTP9: //If the type is HTTP9 then... string[] z = name.Split(new char[] { '/' }, 2); //Split the name string, into a string array, on the / if (z[0].Contains("GET ")) //If the first element of z contains GET { name = z[1]; //The name string now = the second element of z if (locations.TryGetValue(name, out string value)) //If the database (dictionary) contains name { //Stream write this... sw.WriteLine("HTTP/0.9" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n" + "\r\n" + value); if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine("HTTP/0.9" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n" + "\r\n" + value); } //~~~~~DEBUGGING~~~~~ } else //Otherwise... { //Stream write this... sw.WriteLine("HTTP/0.9" + " " + "404" + " " + "Not" + " " + "Found" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine("HTTP/0.9" + " " + "404" + " " + "Not" + " " + "Found" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); } //~~~~~DEBUGGING~~~~~ status = "UNKOWN"; } line = "GET " + name; } else //Otherwise... { name = z[1]; //The name string now = the second element of z if (locations.TryGetValue(name, out string value)) //If the database (dictionary) contains name { locations[name] = location; //The Key's value now = location } else //Otherwise... { locations.Add(name, location); //Add the name and location to the dictionary } //Stream write this... sw.WriteLine("HTTP/0.9" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine("HTTP/0.9" + " " + "200" + " " + "OK" + "\r\n" + "Content-Type:" + " " + "text/plain" + "\r\n"); } //~~~~~DEBUGGING~~~~~ status = "OK"; line = "PUT " + name + " " + location; } break; //Break out of the case case ProtocolType.WHOIS: //If the type is WHOIS then... string[] args = name.Split(new char[] { ' ' }, 2); //Reads the line and splits it on any spaces. //If there are two args then it is an UPDATE. if (args.Length == 2) { if (locations.TryGetValue(args[0], out string value)) //If the database (dictionary) contains name { //If the key is found then it's corresponding value is changed. locations[args[0]] = args[1]; } else { //If the key is not found then it is added with it's corresponding value. locations.Add(args[0], args[1]); } //Stream write this... sw.WriteLine("OK"); //Returns OK to the client. if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine("OK"); } //~~~~~DEBUGGING~~~~~ status = "OK"; line = "PUT " + name + " " + location; } //If there is one arg then it is a LOOKUP. else { if (locations.TryGetValue(args[0], out string value)) //If the database (dictionary) contains name { //If the key is found then it's corresponding value is returned. //Stream write this... sw.WriteLine(value); if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine(value); } //~~~~~DEBUGGING~~~~~ } else //Otherwise... { //If the key isn't found then there is no value to return. //Stream write this... sw.WriteLine("ERROR: no entries found"); if (debugMode) { Console.WriteLine("Reply: \n"); Console.WriteLine("ERROR: no entries found"); } //~~~~~DEBUGGING~~~~~ status = "UNKOWN"; } line = "GET " + name; } break; //Break out of the case } sw.Flush(); //Empties the buffer } catch (Exception e) { if (debugMode) { Console.WriteLine("This should never be reached! An error must have occurred."); } if (debugMode) { Console.WriteLine(e.ToString()); } } finally { if (debugMode) { Console.WriteLine("Connection Terminated.\n~~~~~~~~~~~~~~~~~~~~~~~~~"); //~~~~~DEBUGGING~~~~~ } stream.Close(); //Closes NetworkStream connection.Close(); //Closes the connection log.WriteLog(hostName, line, status); database.WriteDatabase(locations); database.SaveDatabase(); } }