Quick.HttpServer.Request.pas 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. { ***************************************************************************
  2. Copyright (c) 2016-2021 Kike Pérez
  3. Unit : Quick.HttpServer.Request
  4. Description : Http Server Request
  5. Author : Kike Pérez
  6. Version : 1.8
  7. Created : 30/08/2019
  8. Modified : 07/02/2021
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.HttpServer.Request;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. {$IFDEF DEBUG_HTTPSERVER}
  26. Quick.Debug.Utils,
  27. {$ENDIF}
  28. Classes,
  29. SysUtils,
  30. Quick.Commons,
  31. Quick.Arrays,
  32. Quick.Value,
  33. Quick.HttpServer.Types;
  34. type
  35. EHttpRequestError = class(Exception);
  36. type
  37. IHttpRequest = interface
  38. ['{D6B236A5-9D04-4380-8A89-5BD4CC60A1A6}']
  39. function GetPathSegment(aIndex : Integer) : string;
  40. function GetQuery(const aName : string) : TFlexValue;
  41. function GetURL: string;
  42. function GetMethod: TMethodVerb;
  43. function GetCacheControl: string;
  44. function GetClientIP: string;
  45. function GetContent: TStream;
  46. function GetHeaders: TPairList;
  47. function GetHost: string;
  48. function GetPort: Integer;
  49. function GetReferer: string;
  50. function GetUnparsedParams: string;
  51. function GetUserAgent: string;
  52. property URL : string read GetURL;
  53. property Method : TMethodVerb read GetMethod;
  54. property Host : string read GetHost;
  55. property Port : Integer read GetPort;
  56. property Referer : string read GetReferer;
  57. property UserAgent : string read GetUserAgent;
  58. property CacheControl : string read GetCacheControl;
  59. property PathSegment[aIndex : Integer] : string read GetPathSegment;
  60. property UnparsedParams : string read GetUnparsedParams;
  61. property Query[const aName : string] : TFlexValue read GetQuery;
  62. property ClientIP : string read GetClientIP;
  63. property Headers : TPairList read GetHeaders;
  64. property Content : TStream read GetContent;
  65. function ContentAsString : string;
  66. function GetMethodAsString: string;
  67. end;
  68. THttpRequest = class(TInterfacedObject,IHttpRequest)
  69. private
  70. fURL : string;
  71. fMethod : TMethodVerb;
  72. fHost : string;
  73. fPort : Integer;
  74. fReferer : string;
  75. fUserAgent : string;
  76. fCacheControl : string;
  77. fUnparsedParams : string;
  78. fParsedQuery : TFlexPairArray;
  79. fClientIP : string;
  80. fHeaders : TPairList;
  81. fContent : TStream;
  82. fContentType : string;
  83. fContentEncoding : string;
  84. fContentLength : Int64;
  85. function GetPathSegment(aIndex : Integer) : string;
  86. function GetQuery(const aName : string) : TFlexValue;
  87. procedure ParseQuery;
  88. function GetURL: string;
  89. function GetMethod: TMethodVerb;
  90. function GetCacheControl: string;
  91. function GetClientIP: string;
  92. function GetContent: TStream;
  93. function GetHeaders: TPairList;
  94. function GetHost: string;
  95. function GetPort: Integer;
  96. function GetReferer: string;
  97. function GetUnparsedParams: string;
  98. function GetUserAgent: string;
  99. procedure SetURL(const Value: string);
  100. function GetContentEncoding: string;
  101. function GetContentLength: Int64;
  102. function GetContentType: string;
  103. procedure SetContentEncoding(const Value: string);
  104. procedure SetContentLength(const Value: Int64);
  105. procedure SetContentType(const Value: string);
  106. public
  107. constructor Create;
  108. destructor Destroy; override;
  109. property URL : string read GetURL write SetURL;
  110. property Method : TMethodVerb read GetMethod write fMethod;
  111. property Host : string read GetHost write fHost;
  112. property Port : Integer read GetPort write fPort;
  113. property Referer : string read GetReferer write fReferer;
  114. property UserAgent : string read GetUserAgent write fUserAgent;
  115. property CacheControl : string read GetCacheControl write fCacheControl;
  116. property PathSegment[aIndex : Integer] : string read GetPathSegment;
  117. property UnparsedParams : string read GetUnparsedParams write fUnparsedParams;
  118. property Query[const aName : string] : TFlexValue read GetQuery;
  119. property ClientIP : string read GetClientIP write fClientIP;
  120. property Headers : TPairList read GetHeaders write fHeaders;
  121. property Content : TStream read GetContent write fContent;
  122. property ContentType : string read GetContentType write SetContentType;
  123. property ContentEncoding : string read GetContentEncoding write SetContentEncoding;
  124. property ContentLength : Int64 read GetContentLength write SetContentLength;
  125. procedure SetMethodFromString(const aVerbMethod : string);
  126. function GetMethodAsString: string;
  127. function ContentAsString : string;
  128. end;
  129. implementation
  130. function THttpRequest.ContentAsString: string;
  131. begin
  132. {$IFDEF DEBUG_HTTPSERVER}
  133. TDebugger.Trace(Self,'ContentAsString Encode: %s',[ContentEncoding]);
  134. {$ENDIF}
  135. if fContent <> nil then Result := StreamToString(fContent,TEncoding.UTF8);
  136. end;
  137. constructor THttpRequest.Create;
  138. begin
  139. fHeaders := TPairList.Create;
  140. end;
  141. destructor THttpRequest.Destroy;
  142. begin
  143. fHeaders.Free;
  144. inherited;
  145. end;
  146. function THttpRequest.GetCacheControl: string;
  147. begin
  148. Result := fCacheControl;
  149. end;
  150. function THttpRequest.GetClientIP: string;
  151. begin
  152. Result := fClientIP;
  153. end;
  154. function THttpRequest.GetContent: TStream;
  155. begin
  156. Result := fContent;
  157. end;
  158. function THttpRequest.GetContentEncoding: string;
  159. begin
  160. Result := fContentEncoding;
  161. end;
  162. function THttpRequest.GetContentLength: Int64;
  163. begin
  164. Result := fContentLength;
  165. end;
  166. function THttpRequest.GetContentType: string;
  167. begin
  168. Result := fContentType;
  169. end;
  170. function THttpRequest.GetHeaders: TPairList;
  171. begin
  172. Result := fHeaders;
  173. end;
  174. function THttpRequest.GetHost: string;
  175. begin
  176. Result := fHost;
  177. end;
  178. function THttpRequest.GetMethod: TMethodVerb;
  179. begin
  180. Result := fMethod;
  181. end;
  182. function THttpRequest.GetMethodAsString: string;
  183. begin
  184. Result := MethodVerbStr[Integer(fMethod)];
  185. end;
  186. function THttpRequest.GetPathSegment(aIndex: Integer): string;
  187. var
  188. upath : string;
  189. segment : TArray<string>;
  190. begin
  191. try
  192. if fURL.StartsWith('/') then upath := furl.Substring(1)
  193. else upath := fURL;
  194. segment := upath.Split(['/']);
  195. if (High(segment) < aIndex) or (aIndex < 0) then raise EHttpRequestError.CreateFmt('param out of bounds (%d)',[aIndex]);
  196. Result := segment[aIndex];
  197. except
  198. on E : Exception do raise EHttpRequestError.CreateFmt('Error getting url path param : %s',[e.message]);
  199. end;
  200. end;
  201. function THttpRequest.GetPort: Integer;
  202. begin
  203. Result := fPort;
  204. end;
  205. function THttpRequest.GetQuery(const aName: string): TFlexValue;
  206. begin
  207. if fParsedQuery.Count = 0 then ParseQuery;
  208. Result := fParsedQuery.GetValue(aName);
  209. end;
  210. function THttpRequest.GetReferer: string;
  211. begin
  212. Result := fReferer;
  213. end;
  214. function THttpRequest.GetUnparsedParams: string;
  215. begin
  216. Result := fUnparsedParams;
  217. end;
  218. function THttpRequest.GetURL: string;
  219. begin
  220. Result := fURL;
  221. end;
  222. function THttpRequest.GetUserAgent: string;
  223. begin
  224. Result := fUserAgent;
  225. end;
  226. procedure THttpRequest.ParseQuery;
  227. var
  228. param : string;
  229. pair : TFlexPair;
  230. posi : Integer;
  231. begin
  232. for param in fUnparsedParams.Split(['&']) do
  233. begin
  234. posi := Pos('=',param);
  235. pair.Name := Copy(param,1,posi - 1);
  236. pair.Value := param.Substring(posi);
  237. fParsedQuery.Add(pair);
  238. end;
  239. end;
  240. procedure THttpRequest.SetContentEncoding(const Value: string);
  241. begin
  242. fContentEncoding := Value;
  243. end;
  244. procedure THttpRequest.SetContentLength(const Value: Int64);
  245. begin
  246. fContentLength := Value;
  247. end;
  248. procedure THttpRequest.SetContentType(const Value: string);
  249. begin
  250. fContentType := Value;
  251. end;
  252. procedure THttpRequest.SetMethodFromString(const aVerbMethod: string);
  253. var
  254. i : Integer;
  255. begin
  256. fMethod := TMethodVerb.mUNKNOWN;
  257. for i := 0 to Ord(High(TMethodVerb)) do
  258. begin
  259. if CompareText(aVerbMethod,MethodVerbStr[i]) = 0 then
  260. begin
  261. fMethod := TMethodVerb(i);
  262. Exit;
  263. end;
  264. end;
  265. end;
  266. procedure THttpRequest.SetURL(const Value: string);
  267. begin
  268. //remove first slash
  269. if Value.StartsWith('/') then fURL := Value.Substring(1)
  270. else fURL := Value;
  271. //remove last slash
  272. if fURL.EndsWith('/') then fURL := Copy(fURL,0,fURL.Length -1);
  273. end;
  274. end.