mirror of
				https://github.com/esiur/esiur-dotnet.git
				synced 2025-10-30 23:51:34 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			304 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			304 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 
 | |
| /*
 | |
|  
 | |
| Copyright (c) 2017 Ahmed Kh. Zamil
 | |
| 
 | |
| Permission is hereby granted, free of charge, to any person obtaining a copy
 | |
| of this software and associated documentation files (the "Software"), to deal
 | |
| in the Software without restriction, including without limitation the rights
 | |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | |
| copies of the Software, and to permit persons to whom the Software is
 | |
| furnished to do so, subject to the following conditions:
 | |
| 
 | |
| The above copyright notice and this permission notice shall be included in all
 | |
| copies or substantial portions of the Software.
 | |
| 
 | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | |
| SOFTWARE.
 | |
| 
 | |
| */
 | |
| 
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using System.Text;
 | |
| using Esiur.Misc;
 | |
| using Esiur.Data;
 | |
| using System.Net;
 | |
| using System.Text.Json.Serialization;
 | |
| 
 | |
| namespace Esiur.Net.Packets.HTTP;
 | |
| public class HTTPRequestPacket : Packet
 | |
| {
 | |
| 
 | |
| 
 | |
|     public StringKeyList Query;
 | |
|     public HTTPMethod Method;
 | |
|     public StringKeyList Headers;
 | |
| 
 | |
|     public bool WSMode;
 | |
| 
 | |
|     public string Version;
 | |
|     public StringKeyList Cookies; // String
 | |
|     public string URL; /// With query
 | |
|     public string Filename; /// Without query
 | |
| 
 | |
|     public KeyList<string, object> PostForms;
 | |
|     public byte[] Message;
 | |
| 
 | |
| 
 | |
|     private HTTPMethod GetMethod(string method)
 | |
|     {
 | |
|         switch (method.ToLower())
 | |
|         {
 | |
|             case "get":
 | |
|                 return HTTPMethod.GET;
 | |
|             case "post":
 | |
|                 return HTTPMethod.POST;
 | |
|             case "head":
 | |
|                 return HTTPMethod.HEAD;
 | |
|             case "put":
 | |
|                 return HTTPMethod.PUT;
 | |
|             case "delete":
 | |
|                 return HTTPMethod.DELETE;
 | |
|             case "options":
 | |
|                 return HTTPMethod.OPTIONS;
 | |
|             case "trace":
 | |
|                 return HTTPMethod.TRACE;
 | |
|             case "connect":
 | |
|                 return HTTPMethod.CONNECT;
 | |
|             default:
 | |
|                 return HTTPMethod.UNKNOWN;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public override string ToString()
 | |
|     {
 | |
|         return "HTTPRequestPacket"
 | |
|             + "\n\tVersion: " + Version
 | |
|             + "\n\tMethod: " + Method
 | |
|             + "\n\tURL: " + URL
 | |
|             + "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL");
 | |
|     }
 | |
| 
 | |
|     public override long Parse(byte[] data, uint offset, uint ends)
 | |
|     {
 | |
|         string[] sMethod = null;
 | |
|         string[] sLines = null;
 | |
| 
 | |
|         uint headerSize = 0;
 | |
| 
 | |
|         for (uint i = offset; i < ends - 3; i++)
 | |
|         {
 | |
|             if (data[i] == '\r' && data[i + 1] == '\n'
 | |
|                 && data[i + 2] == '\r' && data[i + 3] == '\n')
 | |
|             {
 | |
|                 sLines = Encoding.ASCII.GetString(data, (int)offset, (int)(i - offset)).Split(new string[] { "\r\n" },
 | |
|                     StringSplitOptions.None);
 | |
| 
 | |
|                 headerSize = i + 4;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (headerSize == 0)
 | |
|             return -1;
 | |
| 
 | |
|         Cookies = new StringKeyList();
 | |
|         PostForms = new KeyList<string, object>();
 | |
|         Query = new StringKeyList();
 | |
|         Headers = new StringKeyList();
 | |
| 
 | |
|         sMethod = sLines[0].Split(' ');
 | |
|         Method = GetMethod(sMethod[0].Trim());
 | |
| 
 | |
|         if (sMethod.Length == 3)
 | |
|         {
 | |
|             sMethod[1] = WebUtility.UrlDecode(sMethod[1]);
 | |
|             if (sMethod[1].Length >= 7)
 | |
|             {
 | |
|                 if (sMethod[1].StartsWith("http://"))
 | |
|                 {
 | |
|                     sMethod[1] = sMethod[1].Substring(sMethod[1].IndexOf("/", 7));
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             URL = sMethod[1].Trim();
 | |
| 
 | |
|             if (URL.IndexOf("?", 0) != -1)
 | |
|             {
 | |
|                 Filename = URL.Split(new char[] { '?' }, 2)[0];
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 Filename = URL;
 | |
|             }
 | |
| 
 | |
|             if (Filename.IndexOf("%", 0) != -1)
 | |
|             {
 | |
|                 Filename = WebUtility.UrlDecode(Filename);
 | |
|             }
 | |
| 
 | |
|             Version = sMethod[2].Trim();
 | |
|         }
 | |
| 
 | |
|         // Read all headers
 | |
| 
 | |
|         for (int i = 1; i < sLines.Length; i++)
 | |
|         {
 | |
|             if (sLines[i] == string.Empty)
 | |
|             {
 | |
|                 // Invalid header
 | |
|                 return 0;
 | |
|             }
 | |
| 
 | |
|             if (sLines[i].IndexOf(':') == -1)
 | |
|             {
 | |
|                 // Invalid header
 | |
|                 return 0;
 | |
|             }
 | |
| 
 | |
|             string[] header = sLines[i].Split(new char[] { ':' }, 2);
 | |
| 
 | |
|             header[0] = header[0].ToLower();
 | |
|             Headers[header[0]] = header[1].Trim();
 | |
| 
 | |
|             if (header[0] == "cookie")
 | |
|             {
 | |
|                 string[] cookies = header[1].Split(';');
 | |
| 
 | |
|                 foreach (string cookie in cookies)
 | |
|                 {
 | |
|                     if (cookie.IndexOf('=') != -1)
 | |
|                     {
 | |
|                         string[] splitCookie = cookie.Split('=');
 | |
|                         splitCookie[0] = splitCookie[0].Trim();
 | |
|                         splitCookie[1] = splitCookie[1].Trim();
 | |
|                         if (!Cookies.ContainsKey(splitCookie[0].Trim()))
 | |
|                             Cookies.Add(splitCookie[0], splitCookie[1]);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         if (!Cookies.ContainsKey(cookie.Trim()))
 | |
|                         {
 | |
|                             Cookies.Add(cookie.Trim(), string.Empty);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Query String
 | |
|         if (URL.IndexOf("?", 0) != -1)
 | |
|         {
 | |
|             string[] SQ = URL.Split(new char[] { '?' }, 2)[1].Split('&');
 | |
|             foreach (string S in SQ)
 | |
|             {
 | |
|                 if (S.IndexOf("=", 0) != -1)
 | |
|                 {
 | |
|                     string[] qp = S.Split(new char[] { '=' }, 2);
 | |
| 
 | |
|                     if (!Query.ContainsKey(WebUtility.UrlDecode(qp[0])))
 | |
|                     {
 | |
|                         Query.Add(WebUtility.UrlDecode(qp[0]), WebUtility.UrlDecode(qp[1]));
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if (!Query.ContainsKey(WebUtility.UrlDecode(S)))
 | |
|                     {
 | |
|                         Query.Add(WebUtility.UrlDecode(S), null);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Post Content-Length
 | |
|         if (Method == HTTPMethod.POST)
 | |
|         {
 | |
|             try
 | |
|             {
 | |
| 
 | |
|                 uint postSize = uint.Parse(Headers["content-length"]);
 | |
| 
 | |
|                 // check limit
 | |
|                 if (postSize > data.Length - headerSize)
 | |
|                     return -(postSize - (data.Length - headerSize));
 | |
| 
 | |
| 
 | |
|                 if (
 | |
|                     Headers["content-type"] == null
 | |
|                     || Headers["content-type"] == ""
 | |
|                     || Headers["content-type"].StartsWith("application/x-www-form-urlencoded"))
 | |
|                 {
 | |
|                     string[] PostVars = null;
 | |
|                     PostVars = Encoding.UTF8.GetString(data, (int)headerSize, (int)postSize).Split('&');
 | |
|                     for (int J = 0; J < PostVars.Length; J++)
 | |
|                     {
 | |
|                         if (PostVars[J].IndexOf("=") != -1)
 | |
|                         {
 | |
|                             string key = WebUtility.HtmlDecode(
 | |
|                                 WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[0]));
 | |
|                             if (PostForms.Contains(key))
 | |
|                                 PostForms[key] = WebUtility.HtmlDecode(
 | |
|                                     WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[1]));
 | |
|                             else
 | |
|                                 PostForms.Add(key, WebUtility.HtmlDecode(
 | |
|                                     WebUtility.UrlDecode(PostVars[J].Split(new char[] { '=' }, 2)[1])));
 | |
|                         }
 | |
|                         else
 | |
|                             if (PostForms.Contains("unknown"))
 | |
|                             PostForms["unknown"] = PostForms["unknown"]
 | |
|                                 + "&" + WebUtility.HtmlDecode(WebUtility.UrlDecode(PostVars[J]));
 | |
|                         else
 | |
|                             PostForms.Add("unknown", WebUtility.HtmlDecode(WebUtility.UrlDecode(PostVars[J])));
 | |
|                     }
 | |
|                 }
 | |
|                 else if (Headers["content-type"].StartsWith("multipart/form-data"))
 | |
|                 {
 | |
|                     int st = 1;
 | |
|                     int ed = 0;
 | |
|                     string strBoundry = "--" + Headers["content-type"].Substring(
 | |
|                         Headers["content-type"].IndexOf("boundary=", 0) + 9);
 | |
| 
 | |
|                     string[] sc = Encoding.UTF8.GetString(data, (int)headerSize, (int)postSize).Split(
 | |
|                                                 new string[] { strBoundry }, StringSplitOptions.None);
 | |
| 
 | |
| 
 | |
|                     for (int j = 1; j < sc.Length - 1; j++)
 | |
|                     {
 | |
|                         string[] ps = sc[j].Split(new string[] { "\r\n\r\n" }, 2, StringSplitOptions.None);
 | |
|                         ps[1] = ps[1].Substring(0, ps[1].Length - 2); // remove the empty line
 | |
|                         st = ps[0].IndexOf("name=", 0) + 6;
 | |
|                         ed = ps[0].IndexOf("\"", st);
 | |
|                         PostForms.Add(ps[0].Substring(st, ed - st), ps[1]);
 | |
|                     }
 | |
|                 }
 | |
|                 //else if (Headers["content-type"] == "application/json")
 | |
|                 //{
 | |
|                 //    var json = DC.Clip(data, headerSize, postSize);
 | |
|                 //}
 | |
|                 else
 | |
|                 {
 | |
|                     //PostForms.Add(Headers["content-type"], Encoding.Default.GetString( ));
 | |
|                     Message = data.Clip(headerSize, postSize);
 | |
|                 }
 | |
| 
 | |
|                 return headerSize + postSize;
 | |
| 
 | |
|             }
 | |
|             catch
 | |
|             {
 | |
|                 return 0;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return headerSize;
 | |
|     }
 | |
| }
 |