lhttp.pp 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314
  1. { HTTP server and client components
  2. Copyright (C) 2006-2008 Micha Nelissen
  3. This library is Free software; you can redistribute it and/or modify it
  4. under the terms of the GNU Library General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or (at your
  6. option) any later version.
  7. This program is distributed in the hope that it will be useful, but WITHOUT
  8. ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
  9. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  10. for more details.
  11. You should have received a Copy of the GNU Library General Public License
  12. along with This library; if not, Write to the Free Software Foundation,
  13. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  14. This license has been modified. See file LICENSE.ADDON for more information.
  15. Should you find these sources without a LICENSE File, please contact
  16. me at [email protected]
  17. }
  18. unit lhttp;
  19. {$mode objfpc}{$h+}
  20. {$inline on}
  21. interface
  22. uses
  23. classes, sysutils, lnet, levents, lhttputil, lstrbuffer;
  24. type
  25. TLHTTPMethod = (hmHead, hmGet, hmPost, hmUnknown);
  26. TLHTTPMethods = set of TLHTTPMethod;
  27. TLHTTPParameter = (hpConnection, hpContentLength, hpContentType,
  28. hpAccept, hpAcceptCharset, hpAcceptEncoding, hpAcceptLanguage, hpHost,
  29. hpFrom, hpReferer, hpUserAgent, hpRange, hpTransferEncoding,
  30. hpIfModifiedSince, hpIfUnmodifiedSince, hpCookie);
  31. TLHTTPStatus = (hsUnknown, hsOK, hsNoContent, hsMovedPermanently, hsFound, hsNotModified,
  32. hsBadRequest, hsForbidden, hsNotFound, hsPreconditionFailed, hsRequestTooLong,
  33. hsInternalError, hsNotImplemented, hsNotAllowed);
  34. TLHTTPTransferEncoding = (teIdentity, teChunked);
  35. TLHTTPClientError = (ceNone, ceMalformedStatusLine, ceVersionNotSupported,
  36. ceUnsupportedEncoding);
  37. const
  38. HTTPDisconnectStatuses = [hsBadRequest, hsRequestTooLong, hsForbidden,
  39. hsInternalError, hsNotAllowed];
  40. HTTPMethodStrings: array[TLHTTPMethod] of string =
  41. ('HEAD', 'GET', 'POST', '');
  42. HTTPParameterStrings: array[TLHTTPParameter] of string =
  43. ('CONNECTION', 'CONTENT-LENGTH', 'CONTENT-TYPE', 'ACCEPT',
  44. 'ACCEPT-CHARSET', 'ACCEPT-ENCODING', 'ACCEPT-LANGUAGE', 'HOST',
  45. 'FROM', 'REFERER', 'USER-AGENT', 'RANGE', 'TRANSFER-ENCODING',
  46. 'IF-MODIFIED-SINCE', 'IF-UNMODIFIED-SINCE', 'COOKIE');
  47. HTTPStatusCodes: array[TLHTTPStatus] of dword =
  48. (0, 200, 204, 301, 302, 304, 400, 403, 404, 412, 414, 500, 501, 504);
  49. HTTPTexts: array[TLHTTPStatus] of string =
  50. ('', 'OK', 'No Content', 'Moved Permanently', 'Found', 'Not Modified', 'Bad Request', 'Forbidden',
  51. 'Not Found', 'Precondition Failed', 'Request Too Long', 'Internal Error',
  52. 'Method Not Implemented', 'Method Not Allowed');
  53. HTTPDescriptions: array[TLHTTPStatus] of string = (
  54. { hsUnknown }
  55. '',
  56. { hsOK }
  57. '',
  58. { hsNoContent }
  59. '',
  60. { hsMovedPermanently }
  61. '',
  62. { hsFound }
  63. '',
  64. { hsNotModified }
  65. '',
  66. { hsBadRequest }
  67. '<html><head><title>400 Bad Request</title></head><body>'+#10+
  68. '<h1>Bad Request</h1>'+#10+
  69. '<p>Your browser did a request this server did not understand.</p>'+#10+
  70. '</body></html>'+#10,
  71. { hsForbidden }
  72. '<html><head><title>403 Forbidden</title></head><body>'+#10+
  73. '<h1>Forbidden</h1>'+#10+
  74. '<p>You do not have permission to access this resource.</p>'+#10+
  75. '</body></html>'+#10,
  76. { hsNotFound }
  77. '<html><head><title>404 Not Found</title></head><body>'+#10+
  78. '<h1>Not Found</h1>'+#10+
  79. '<p>The requested URL was not found on this server.</p>'+#10+
  80. '</body></html>'+#10,
  81. { hsPreconditionFailed }
  82. '<html><head><title>412 Precondition Failed</title></head><body>'+#10+
  83. '<h1>Precondition Failed</h1>'+#10+
  84. '<p>The precondition on the request evaluated to false.</p>'+#10+
  85. '</body></html>'+#10,
  86. { hsRequestTooLong }
  87. '<html><head><title>414 Request Too Long</title></head><body>'+#10+
  88. '<h1>Bad Request</h1>'+#10+
  89. '<p>Your browser did a request that was too long for this server to parse.</p>'+#10+
  90. '</body></html>'+#10,
  91. { hsInternalError }
  92. '<html><head><title>500 Internal Error</title></head><body>'+#10+
  93. '<h1>Internal Error</h1>'+#10+
  94. '<p>An error occurred while generating the content for this request.</p>'+#10+
  95. '</body></html>'+#10,
  96. { hsNotImplemented }
  97. '<html><head><title>501 Method Not Implemented</title></head><body>'+#10+
  98. '<h1>Method Not Implemented</h1>'+#10+
  99. '<p>The method used in the request is invalid.</p>'+#10+
  100. '</body></html>'+#10,
  101. { hsNotAllowed }
  102. '<html><head><title>504 Method Not Allowed</title></head><body>'+#10+
  103. '<h1>Method Not Allowed</h1>'+#10+
  104. '<p>The method used in the request is not allowed on the resource specified in the URL.</p>'+#10+
  105. '</body></html>'+#10);
  106. type
  107. TLHTTPSocket = class;
  108. TLHTTPConnection = class;
  109. TLHTTPClientSocket = class;
  110. PRequestInfo = ^TRequestInfo;
  111. TRequestInfo = record
  112. RequestType: TLHTTPMethod;
  113. DateTime: TDateTime;
  114. Method: pansichar;
  115. Argument: pansichar;
  116. QueryParams: pansichar;
  117. VersionStr: pansichar;
  118. Version: dword;
  119. end;
  120. PClientRequest = ^TClientRequest;
  121. TClientRequest = record
  122. Method: TLHTTPMethod;
  123. URI: string;
  124. QueryParams: string;
  125. RangeStart: qword;
  126. RangeEnd: qword;
  127. end;
  128. PClientResponse = ^TClientResponse;
  129. TClientResponse = record
  130. Status: TLHTTPStatus;
  131. Version: dword;
  132. Reason: string;
  133. end;
  134. PHeaderOutInfo = ^THeaderOutInfo;
  135. THeaderOutInfo = record
  136. ContentLength: integer;
  137. TransferEncoding: TLHTTPTransferEncoding;
  138. ExtraHeaders: TStringBuffer;
  139. Version: dword;
  140. end;
  141. PResponseInfo = ^TResponseInfo;
  142. TResponseInfo = record
  143. Status: TLHTTPStatus;
  144. ContentType: Ansistring;
  145. ContentCharset: Ansistring;
  146. LastModified: TDateTime;
  147. end;
  148. TWriteBlockStatus = (wsPendingData, wsWaitingData, wsDone);
  149. TWriteBlockMethod = function: TWriteBlockStatus of object;
  150. TOutputItem = class(TObject)
  151. protected
  152. FBuffer: PAnsiChar;
  153. FBufferPos: integer;
  154. FBufferSize: integer;
  155. FBufferOffset: integer;
  156. FOutputPending: boolean;
  157. FEof: boolean;
  158. FPrev: TOutputItem;
  159. FNext: TOutputItem;
  160. FPrevDelayFree: TOutputItem;
  161. FNextDelayFree: TOutputItem;
  162. FSocket: TLHTTPSocket;
  163. FWriteBlock: TWriteBlockMethod;
  164. procedure DoneInput; virtual;
  165. function HandleInput(ABuffer: PAnsiChar; ASize: integer): integer; virtual;
  166. function WriteBlock: TWriteBlockStatus; virtual;
  167. public
  168. constructor Create(ASocket: TLHTTPSocket);
  169. destructor Destroy; override;
  170. procedure LogError(const AMessage: string);
  171. property Socket: TLHTTPSocket read FSocket;
  172. end;
  173. TProcMethod = procedure of object;
  174. TBufferOutput = class(TOutputItem)
  175. protected
  176. FPrepareBuffer: TProcMethod;
  177. FFinishBuffer: TProcMethod;
  178. FBufferMemSize: integer;
  179. procedure PrepareBuffer;
  180. procedure PrepareChunk;
  181. procedure FinishBuffer;
  182. procedure FinishChunk;
  183. procedure SelectChunked;
  184. procedure SelectBuffered;
  185. procedure SelectPlain;
  186. procedure PrependBufferOutput(MinBufferSize: integer);
  187. procedure PrependStreamOutput(AStream: TStream; AFree: boolean);
  188. function FillBuffer: TWriteBlockStatus; virtual; abstract;
  189. function WriteChunk: TWriteBlockStatus;
  190. function WriteBuffer: TWriteBlockStatus;
  191. function WritePlain: TWriteBlockStatus;
  192. function WriteBlock: TWriteBlockStatus; override;
  193. public
  194. constructor Create(ASocket: TLHTTPSocket);
  195. destructor Destroy; override;
  196. procedure Add(ABuf: pointer; ASize: integer);
  197. procedure Add(const AStr: string);
  198. procedure Add(AStream: TStream; AQueue: boolean = false; AFree: boolean = true);
  199. end;
  200. TMemoryOutput = class(TOutputItem)
  201. protected
  202. FFreeBuffer: boolean;
  203. public
  204. constructor Create(ASocket: TLHTTPSocket; ABuffer: pointer;
  205. ABufferOffset, ABufferSize: integer; AFreeBuffer: boolean);
  206. destructor Destroy; override;
  207. end;
  208. TStreamOutput = class(TBufferOutput)
  209. protected
  210. FStream: TStream;
  211. FFreeStream: boolean;
  212. FStreamSize: integer;
  213. function FillBuffer: TWriteBlockStatus; override;
  214. public
  215. constructor Create(ASocket: TLHTTPSocket; AStream: TStream; AFreeStream: boolean);
  216. destructor Destroy; override;
  217. end;
  218. TMemoryStreamOutput = class(TOutputItem)
  219. protected
  220. FFreeStream: boolean;
  221. FStream: TMemoryStream;
  222. function WriteBlock: TWriteBlockStatus; override;
  223. public
  224. constructor Create(ASocket: TLHTTPSocket; AStream: TMemoryStream; AFreeStream: boolean);
  225. destructor Destroy; override;
  226. end;
  227. TChunkState = (csInitial, csData, csDataEnd, csTrailer, csFinished);
  228. TLHTTPParameterArray = array[TLHTTPParameter] of PAnsiChar;
  229. TParseBufferMethod = function: boolean of object;
  230. TLInputEvent = function(ASocket: TLHTTPClientSocket; ABuffer: PAnsiChar; ASize: integer): integer of object;
  231. TLCanWriteEvent = procedure(ASocket: TLHTTPClientSocket; var OutputEof: TWriteBlockStatus) of object;
  232. TLHTTPClientEvent = procedure(ASocket: TLHTTPClientSocket) of object;
  233. TLHTTPConnection = class(TLTcp)
  234. protected
  235. procedure CanSendEvent(aSocket: TLHandle); override;
  236. procedure LogAccess(const AMessage: string); virtual;
  237. procedure ReceiveEvent(aSocket: TLHandle); override;
  238. public
  239. destructor Destroy; override;
  240. end;
  241. TLHTTPSocket = class(TLSocket)
  242. protected
  243. FBuffer: PAnsiChar;
  244. FBufferPos: PAnsiChar;
  245. FBufferEnd: PAnsiChar;
  246. FBufferSize: integer;
  247. FRequestBuffer: PAnsiChar;
  248. FRequestPos: PAnsiChar;
  249. FRequestInputDone: boolean;
  250. FRequestHeaderDone: boolean;
  251. FOutputDone: boolean;
  252. FInputRemaining: integer;
  253. FChunkState: TChunkState;
  254. FCurrentInput: TOutputItem;
  255. FCurrentOutput: TOutputItem;
  256. FLastOutput: TOutputItem;
  257. FKeepAlive: boolean;
  258. FParseBuffer: TParseBufferMethod;
  259. FParameters: TLHTTPParameterArray;
  260. FDelayFreeItems: TOutputItem;
  261. procedure AddContentLength(ALength: integer); virtual; abstract;
  262. function CalcAvailableBufferSpace: integer;
  263. procedure DelayFree(AOutputItem: TOutputItem);
  264. procedure DoneBuffer(AOutput: TBufferOutput); virtual;
  265. procedure FreeDelayFreeItems;
  266. procedure LogAccess(const AMessage: string); virtual;
  267. procedure LogMessage; virtual;
  268. procedure FlushRequest; virtual;
  269. procedure PackRequestBuffer;
  270. procedure PackInputBuffer;
  271. function ParseRequest: boolean;
  272. function ParseEntityPlain: boolean;
  273. function ParseEntityChunked: boolean;
  274. procedure ParseLine(pLineEnd: PAnsiChar); virtual;
  275. procedure ParseParameterLine(pLineEnd: PAnsiChar);
  276. function ProcessEncoding: boolean;
  277. procedure ProcessHeaders; virtual; abstract;
  278. procedure RelocateVariable(var AVar: PAnsiChar);
  279. procedure RelocateVariables; virtual;
  280. procedure ResetDefaults; virtual;
  281. function SetupEncoding(AOutputItem: TBufferOutput; AHeaderOut: PHeaderOutInfo): boolean;
  282. procedure WriteError(AStatus: TLHTTPStatus); virtual;
  283. public
  284. constructor Create; override;
  285. destructor Destroy; override;
  286. procedure AddToOutput(AOutputItem: TOutputItem);
  287. procedure Disconnect(const Forced: Boolean = True); override;
  288. procedure PrependOutput(ANewItem, AItem: TOutputItem);
  289. procedure RemoveOutput(AOutputItem: TOutputItem);
  290. procedure HandleReceive;
  291. function ParseBuffer: boolean;
  292. procedure WriteBlock;
  293. property Parameters: TLHTTPParameterArray read FParameters;
  294. end;
  295. { http server }
  296. TSetupEncodingState = (seNone, seWaitHeaders, seStartHeaders);
  297. TLHTTPServerSocket = class(TLHTTPSocket)
  298. protected
  299. FLogMessage: TStringBuffer;
  300. FSetupEncodingState: TSetupEncodingState;
  301. procedure AddContentLength(ALength: integer); override;
  302. procedure DoneBuffer(AOutput: TBufferOutput); override;
  303. procedure FlushRequest; override;
  304. function HandleURI: TOutputItem; virtual;
  305. procedure LogAccess(const AMessage: string); override;
  306. procedure LogMessage; override;
  307. procedure RelocateVariables; override;
  308. procedure ResetDefaults; override;
  309. procedure ParseLine(pLineEnd: PAnsiChar); override;
  310. procedure ParseRequestLine(pLineEnd: PAnsiChar);
  311. function PrepareResponse(AOutputItem: TOutputItem; ACustomErrorMessage: boolean): boolean;
  312. procedure ProcessHeaders; override;
  313. procedure WriteError(AStatus: TLHTTPStatus); override;
  314. procedure WriteHeaders(AHeaderResponse, ADataResponse: TOutputItem);
  315. public
  316. FHeaderOut: THeaderOutInfo;
  317. FRequestInfo: TRequestInfo;
  318. FResponseInfo: TResponseInfo;
  319. constructor Create; override;
  320. destructor Destroy; override;
  321. function SetupEncoding(AOutputItem: TBufferOutput): boolean;
  322. procedure StartMemoryResponse(AOutputItem: TMemoryOutput; ACustomErrorMessage: boolean = false);
  323. procedure StartResponse(AOutputItem: TBufferOutput; ACustomErrorMessage: boolean = false);
  324. end;
  325. TURIHandler = class(TObject)
  326. private
  327. FNext: TURIHandler;
  328. FMethods: TLHTTPMethods;
  329. protected
  330. function HandleURI(ASocket: TLHTTPServerSocket): TOutputItem; virtual; abstract;
  331. procedure RegisterWithEventer(AEventer: TLEventer); virtual;
  332. public
  333. constructor Create;
  334. property Methods: TLHTTPMethods read FMethods write FMethods;
  335. end;
  336. TLAccessEvent = procedure(AMessage: string) of object;
  337. TLHTTPServer = class(TLHTTPConnection)
  338. protected
  339. FHandlerList: TURIHandler;
  340. FLogMessageTZString: string;
  341. FServerSoftware: string;
  342. FOnAccess: TLAccessEvent;
  343. function HandleURI(ASocket: TLHTTPServerSocket): TOutputItem;
  344. protected
  345. procedure LogAccess(const AMessage: string); override;
  346. procedure RegisterWithEventer; override;
  347. public
  348. constructor Create(AOwner: TComponent); override;
  349. procedure RegisterHandler(AHandler: TURIHandler);
  350. property ServerSoftware: string read FServerSoftware write FServerSoftware;
  351. property OnAccess: TLAccessEvent read FOnAccess write FOnAccess;
  352. end;
  353. { http client }
  354. TLHTTPClientSocket = class(TLHTTPSocket)
  355. protected
  356. FRequest: PClientRequest;
  357. FResponse: PClientResponse;
  358. FHeaderOut: PHeaderOutInfo;
  359. FError: TLHTTPClientError;
  360. procedure AddContentLength(ALength: integer); override;
  361. function GetResponseReason: string;
  362. function GetResponseStatus: TLHTTPStatus;
  363. procedure Cancel(AError: TLHTTPClientError);
  364. procedure ParseLine(pLineEnd: PAnsiChar); override;
  365. procedure ParseStatusLine(pLineEnd: PAnsiChar);
  366. procedure ProcessHeaders; override;
  367. procedure ResetDefaults; override;
  368. public
  369. constructor Create; override;
  370. destructor Destroy; override;
  371. procedure SendRequest;
  372. property Error: TLHTTPClientError read FError write FError;
  373. property Response: PClientResponse read FResponse;
  374. property ResponseReason: string read GetResponseReason;
  375. property ResponseStatus: TLHTTPStatus read GetResponseStatus;
  376. end;
  377. TLHTTPClientState = (hcsIdle, hcsWaiting, hcsReceiving);
  378. TLHTTPClient = class(TLHTTPConnection)
  379. protected
  380. FRequest: TClientRequest;
  381. FResponse: TClientResponse;
  382. FHeaderOut: THeaderOutInfo;
  383. FState: TLHTTPClientState;
  384. FPendingResponses: integer;
  385. FOutputEof: boolean;
  386. FOnCanWrite: TLCanWriteEvent;
  387. FOnDoneInput: TLHTTPClientEvent;
  388. FOnInput: TLInputEvent;
  389. FOnProcessHeaders: TLHTTPClientEvent;
  390. procedure ConnectEvent(aSocket: TLHandle); override;
  391. procedure DoDoneInput(ASocket: TLHTTPClientSocket);
  392. function DoHandleInput(ASocket: TLHTTPClientSocket; ABuffer: PAnsiChar; ASize: integer): integer;
  393. procedure DoProcessHeaders(ASocket: TLHTTPClientSocket);
  394. function DoWriteBlock(ASocket: TLHTTPClientSocket): TWriteBlockStatus;
  395. function InitSocket(aSocket: TLSocket): TLSocket; override;
  396. procedure InternalSendRequest;
  397. public
  398. constructor Create(AOwner: TComponent); override;
  399. destructor Destroy; override;
  400. procedure AddExtraHeader(const AHeader: string);
  401. procedure AddCookie(const AName, AValue: string; const APath: string = '';
  402. const ADomain: string = ''; const AVersion: string = '0');
  403. procedure ResetRange;
  404. procedure SendRequest;
  405. property ContentLength: integer read FHeaderOut.ContentLength write FHeaderOut.ContentLength;
  406. property Method: TLHTTPMethod read FRequest.Method write FRequest.Method;
  407. property PendingResponses: integer read FPendingResponses;
  408. property RangeStart: qword read FRequest.RangeStart write FRequest.RangeStart;
  409. property RangeEnd: qword read FRequest.RangeEnd write FRequest.RangeEnd;
  410. property Request: TClientRequest read FRequest;
  411. property State: TLHTTPClientState read FState;
  412. property URI: string read FRequest.URI write FRequest.URI;
  413. property Response: TClientResponse read FResponse;
  414. property OnCanWrite: TLCanWriteEvent read FOnCanWrite write FOnCanWrite;
  415. property OnDoneInput: TLHTTPClientEvent read FOnDoneInput write FOnDoneInput;
  416. property OnInput: TLInputEvent read FOnInput write FOnInput;
  417. property OnProcessHeaders: TLHTTPClientEvent read FOnProcessHeaders write FOnProcessHeaders;
  418. end;
  419. implementation
  420. uses
  421. lCommon;
  422. const
  423. RequestBufferSize = 1024;
  424. DataBufferSize = 16*1024;
  425. BufferEmptyToWriteStatus: array[boolean] of TWriteBlockStatus =
  426. (wsPendingData, wsDone);
  427. EofToWriteStatus: array[boolean] of TWriteBlockStatus =
  428. (wsWaitingData, wsDone);
  429. { helper functions }
  430. function TrySingleDigit(ADigit: char; out OutDigit: byte): boolean;
  431. begin
  432. Result := (ord(ADigit) >= ord('0')) and (ord(ADigit) <= ord('9'));
  433. if not Result then exit;
  434. OutDigit := ord(ADigit) - ord('0');
  435. end;
  436. function HTTPVersionCheck(AStr, AStrEnd: PAnsiChar; out AVersion: dword): boolean;
  437. var
  438. lMajorVersion, lMinorVersion: byte;
  439. begin
  440. Result := ((AStrEnd-AStr) = 8)
  441. and CompareMem(AStr, PAnsiChar('HTTP/'), 5)
  442. and TrySingleDigit(AStr[5], lMajorVersion)
  443. and (AStr[6] = '.')
  444. and TrySingleDigit(AStr[7], lMinorVersion);
  445. AVersion := lMajorVersion * 10 + lMinorVersion;
  446. end;
  447. function CodeToHTTPStatus(ACode: dword): TLHTTPStatus;
  448. begin
  449. for Result := Low(TLHTTPStatus) to High(TLHTTPStatus) do
  450. if HTTPStatusCodes[Result] = ACode then exit;
  451. Result := hsUnknown;
  452. end;
  453. const
  454. HexDigits: array[0..15] of char = '0123456789ABCDEF';
  455. function HexReverse(AValue: dword; ABuffer: PAnsiChar): integer;
  456. begin
  457. Result := 0;
  458. repeat
  459. ABuffer^ := HexDigits[AValue and $F];
  460. AValue := AValue shr 4;
  461. Dec(ABuffer);
  462. Inc(Result);
  463. until AValue = 0;
  464. end;
  465. procedure HexToInt(ABuffer: PAnsiChar; out AValue: dword; out ACode: integer);
  466. var
  467. Val, Incr: dword;
  468. Start: PAnsiChar;
  469. begin
  470. Val := 0;
  471. ACode := 0;
  472. Start := ABuffer;
  473. while ABuffer^ <> #0 do
  474. begin
  475. if (ABuffer^ >= '0') and (ABuffer^ <= '9') then
  476. Incr := ord(ABuffer^) - ord('0')
  477. else if (ABuffer^ >= 'A') and (ABuffer^ <= 'F') then
  478. Incr := ord(ABuffer^) - ord('A') + 10
  479. else if (ABuffer^ >= 'a') and (ABuffer^ <= 'f') then
  480. Incr := ord(ABuffer^) - ord('a') + 10
  481. else begin
  482. ACode := ABuffer - Start + 1;
  483. break;
  484. end;
  485. Val := (Val shl 4) + Incr;
  486. Inc(ABuffer);
  487. end;
  488. AValue := Val;
  489. end;
  490. function EscapeCookie(const AInput: string): string;
  491. begin
  492. Result := StringReplace(AInput, ';', '%3B', [rfReplaceAll]);
  493. end;
  494. { TURIHandler }
  495. constructor TURIHandler.Create;
  496. begin
  497. FMethods := [hmHead, hmGet, hmPost];
  498. end;
  499. procedure TURIHandler.RegisterWithEventer(AEventer: TLEventer);
  500. begin
  501. end;
  502. { TOutputItem }
  503. constructor TOutputItem.Create(ASocket: TLHTTPSocket);
  504. begin
  505. FSocket := ASocket;
  506. inherited Create;
  507. end;
  508. destructor TOutputItem.Destroy;
  509. begin
  510. if FSocket.FCurrentInput = Self then
  511. FSocket.FCurrentInput := nil;
  512. if FPrevDelayFree = nil then
  513. FSocket.FDelayFreeItems := FNextDelayFree
  514. else
  515. FPrevDelayFree.FNextDelayFree := FNextDelayFree;
  516. if FNextDelayFree <> nil then
  517. FNextDelayFree.FPrevDelayFree := FPrevDelayFree;
  518. inherited;
  519. end;
  520. procedure TOutputItem.DoneInput;
  521. begin
  522. end;
  523. function TOutputItem.HandleInput(ABuffer: PAnsiChar; ASize: integer): integer;
  524. begin
  525. { discard input }
  526. Result := ASize;
  527. end;
  528. procedure TOutputItem.LogError(const AMessage: string);
  529. begin
  530. FSocket.LogError(AMessage, 0);
  531. end;
  532. function TOutputItem.WriteBlock: TWriteBlockStatus;
  533. var
  534. lWritten: integer;
  535. begin
  536. if FOutputPending then
  537. begin
  538. if FBufferSize > FBufferPos then
  539. begin
  540. lWritten := FSocket.Send(FBuffer[FBufferPos], FBufferSize-FBufferPos);
  541. Inc(FBufferPos, lWritten);
  542. end;
  543. FOutputPending := FBufferPos < FBufferSize;
  544. Result := BufferEmptyToWriteStatus[not FOutputPending];
  545. end else
  546. Result := EofToWriteStatus[FEof];
  547. end;
  548. const
  549. ReserveChunkBytes = 12;
  550. constructor TBufferOutput.Create(ASocket: TLHTTPSocket);
  551. begin
  552. inherited;
  553. GetMem(FBuffer, DataBufferSize);
  554. FWriteBlock := @WritePlain;
  555. FPrepareBuffer := @PrepareBuffer;
  556. FFinishBuffer := @FinishBuffer;
  557. FBufferMemSize := DataBufferSize;
  558. end;
  559. destructor TBufferOutput.Destroy;
  560. begin
  561. inherited;
  562. FreeMem(FBuffer);
  563. end;
  564. procedure TBufferOutput.Add(ABuf: pointer; ASize: integer);
  565. var
  566. copySize: integer;
  567. begin
  568. repeat
  569. copySize := FBufferSize-FBufferPos;
  570. if copySize > ASize then
  571. copySize := ASize;
  572. Move(ABuf^, FBuffer[FBufferPos], copySize);
  573. Inc(FBufferPos, copySize);
  574. Dec(ASize, copySize);
  575. if ASize = 0 then
  576. break;
  577. PrependBufferOutput(ASize);
  578. until false;
  579. end;
  580. procedure TBufferOutput.Add(const AStr: string);
  581. begin
  582. Add(PAnsiChar(AStr), Length(AStr));
  583. end;
  584. procedure TBufferOutput.PrependStreamOutput(AStream: TStream; AFree: boolean);
  585. begin
  586. if AStream is TMemoryStream then
  587. FSocket.PrependOutput(TMemoryStreamOutput.Create(FSocket, TMemoryStream(AStream), AFree), Self)
  588. else
  589. FSocket.PrependOutput(TStreamOutput.Create(FSocket, AStream, AFree), Self);
  590. end;
  591. procedure TBufferOutput.Add(AStream: TStream; AQueue: boolean = false;
  592. AFree: boolean = true);
  593. var
  594. size, copySize: integer;
  595. begin
  596. size := AStream.Size - AStream.Position;
  597. repeat
  598. copySize := FBufferSize-FBufferPos;
  599. if copySize > size then
  600. copySize := size;
  601. AStream.Read(FBuffer[FBufferPos], copySize);
  602. Inc(FBufferPos, copySize);
  603. Dec(size, copySize);
  604. if size = 0 then
  605. break;
  606. if AQueue then
  607. begin
  608. PrependBufferOutput(0);
  609. PrependStreamOutput(AStream, AFree);
  610. end else begin
  611. PrependBufferOutput(size);
  612. end;
  613. until false;
  614. end;
  615. procedure TBufferOutput.PrepareChunk;
  616. begin
  617. { 12 bytes for starting space, 7 bytes to end: <CR><LF>0<CR><LF><CR><LF> }
  618. FBufferPos := ReserveChunkBytes;
  619. FBufferOffset := FBufferPos;
  620. FBufferSize := FBufferMemSize-7;
  621. end;
  622. procedure TBufferOutput.FinishChunk;
  623. var
  624. lOffset: integer;
  625. begin
  626. lOffset := HexReverse(FBufferPos-FBufferOffset, FBuffer+FBufferOffset-3);
  627. FBuffer[FBufferOffset-2] := #13;
  628. FBuffer[FBufferOffset-1] := #10;
  629. FBuffer[FBufferPos] := #13;
  630. FBuffer[FBufferPos+1] := #10;
  631. FBufferSize := FBufferPos+2;
  632. FBufferPos := FBufferOffset-lOffset-2;
  633. end;
  634. procedure TBufferOutput.PrepareBuffer;
  635. { also for "plain" encoding }
  636. begin
  637. FBufferPos := 0;
  638. FBufferOffset := 0;
  639. FBufferSize := FBufferMemSize;
  640. end;
  641. procedure TBufferOutput.FinishBuffer;
  642. begin
  643. { nothing to do }
  644. end;
  645. procedure TBufferOutput.PrependBufferOutput(MinBufferSize: integer);
  646. begin
  647. FFinishBuffer();
  648. FSocket.PrependOutput(TMemoryOutput.Create(FSocket, FBuffer, FBufferOffset,
  649. FBufferPos, true), Self);
  650. FBufferMemSize := MinBufferSize;
  651. if FBufferMemSize < DataBufferSize then
  652. FBufferMemSize := DataBufferSize;
  653. FBuffer := GetMem(FBufferMemSize);
  654. FPrepareBuffer();
  655. end;
  656. function TBufferOutput.WriteChunk: TWriteBlockStatus;
  657. begin
  658. if not FOutputPending and not FEof then
  659. begin
  660. Result := FillBuffer;
  661. FEof := Result = wsDone;
  662. FOutputPending := FBufferPos > FBufferOffset;
  663. if FOutputPending then
  664. FinishChunk;
  665. if FEof then
  666. begin
  667. if not FOutputPending then
  668. begin
  669. { FBufferPos/Size still in "fill mode" }
  670. FBufferSize := 0;
  671. FBufferPos := 0;
  672. FOutputPending := true;
  673. end;
  674. FBuffer[FBufferSize] := '0';
  675. FBuffer[FBufferSize+1] := #13;
  676. FBuffer[FBufferSize+2] := #10;
  677. { no trailer }
  678. FBuffer[FBufferSize+3] := #13;
  679. FBuffer[FBufferSize+4] := #10;
  680. inc(FBufferSize, 5);
  681. end;
  682. end else
  683. Result := EofToWriteStatus[FEof];
  684. if FOutputPending then
  685. begin
  686. Result := inherited WriteBlock;
  687. if (Result = wsDone) and not FEof then
  688. begin
  689. Result := wsPendingData;
  690. PrepareChunk;
  691. end;
  692. end;
  693. end;
  694. function TBufferOutput.WriteBuffer: TWriteBlockStatus;
  695. begin
  696. if not FOutputPending then
  697. begin
  698. Result := FillBuffer;
  699. FEof := Result = wsDone;
  700. FOutputPending := FEof;
  701. if FOutputPending or (FBufferPos = FBufferSize) then
  702. begin
  703. if FBufferPos > FBufferOffset then
  704. begin
  705. FSocket.AddContentLength(FBufferPos-FBufferOffset);
  706. if not FEof then
  707. PrependBufferOutput(0)
  708. else begin
  709. FBufferSize := FBufferPos;
  710. FBufferPos := FBufferOffset;
  711. end;
  712. end else begin
  713. FBufferPos := 0;
  714. FBufferSize := 0;
  715. end;
  716. if FEof then
  717. FSocket.DoneBuffer(Self);
  718. end;
  719. end else
  720. Result := EofToWriteStatus[FEof];
  721. if Result = wsDone then
  722. Result := inherited WriteBlock;
  723. end;
  724. function TBufferOutput.WritePlain: TWriteBlockStatus;
  725. begin
  726. if not FOutputPending then
  727. begin
  728. Result := FillBuffer;
  729. FEof := Result = wsDone;
  730. if FBufferPos > FBufferOffset then
  731. begin
  732. FOutputPending := true;
  733. FBufferSize := FBufferPos;
  734. FBufferPos := FBufferOffset;
  735. end else begin
  736. FBufferSize := 0;
  737. FBufferPos := 0;
  738. end;
  739. end;
  740. Result := inherited WriteBlock;
  741. if Result <> wsPendingData then
  742. begin
  743. PrepareBuffer;
  744. if not FEof then
  745. Result := wsPendingData;
  746. end;
  747. end;
  748. function TBufferOutput.WriteBlock: TWriteBlockStatus;
  749. begin
  750. Result := FWriteBlock();
  751. end;
  752. procedure TBufferOutput.SelectChunked;
  753. begin
  754. FPrepareBuffer := @PrepareChunk;
  755. FWriteBlock := @WriteChunk;
  756. FFinishBuffer := @FinishChunk;
  757. PrepareChunk;
  758. end;
  759. procedure TBufferOutput.SelectBuffered;
  760. begin
  761. FPrepareBuffer := @PrepareBuffer;
  762. FWriteBlock := @WriteBuffer;
  763. FFinishBuffer := @FinishBuffer;
  764. PrepareBuffer;
  765. end;
  766. procedure TBufferOutput.SelectPlain;
  767. begin
  768. FPrepareBuffer := @PrepareBuffer;
  769. FWriteBlock := @WritePlain;
  770. FFinishBuffer := @FinishBuffer;
  771. PrepareBuffer;
  772. end;
  773. { TMemoryOutput }
  774. constructor TMemoryOutput.Create(ASocket: TLHTTPSocket; ABuffer: pointer;
  775. ABufferOffset, ABufferSize: integer; AFreeBuffer: boolean);
  776. begin
  777. inherited Create(ASocket);
  778. FBuffer := ABuffer;
  779. FBufferPos := ABufferOffset;
  780. FBufferSize := ABufferSize;
  781. FFreeBuffer := AFreeBuffer;
  782. FOutputPending := true;
  783. end;
  784. destructor TMemoryOutput.Destroy;
  785. begin
  786. inherited;
  787. if FFreeBuffer then
  788. FreeMem(FBuffer);
  789. end;
  790. { TStreamOutput }
  791. constructor TStreamOutput.Create(ASocket: TLHTTPSocket; AStream: TStream; AFreeStream: boolean);
  792. begin
  793. inherited Create(ASocket);
  794. FStream := AStream;
  795. FFreeStream := AFreeStream;
  796. FStreamSize := AStream.Size;
  797. end;
  798. destructor TStreamOutput.Destroy;
  799. begin
  800. if FFreeStream then
  801. FStream.Free;
  802. inherited;
  803. end;
  804. function TStreamOutput.FillBuffer: TWriteBlockStatus;
  805. var
  806. lRead: integer;
  807. begin
  808. lRead := FStream.Read(FBuffer[FBufferPos], FBufferSize-FBufferPos);
  809. Inc(FBufferPos, lRead);
  810. Result := BufferEmptyToWriteStatus[FStream.Position >= FStreamSize];
  811. end;
  812. { TMemoryStreamOutput }
  813. constructor TMemoryStreamOutput.Create(ASocket: TLHTTPSocket; AStream: TMemoryStream;
  814. AFreeStream: boolean);
  815. begin
  816. inherited Create(ASocket);
  817. FStream := AStream;
  818. FFreeStream := AFreeStream;
  819. FOutputPending := true;
  820. end;
  821. destructor TMemoryStreamOutput.Destroy;
  822. begin
  823. if FFreeStream then
  824. FStream.Free;
  825. inherited;
  826. end;
  827. function TMemoryStreamOutput.WriteBlock: TWriteBlockStatus;
  828. var
  829. lWritten: integer;
  830. begin
  831. if not FOutputPending then
  832. exit(wsDone);
  833. lWritten := FSocket.Send(PByte(FStream.Memory)[FStream.Position], FStream.Size-FStream.Position);
  834. FStream.Position := FStream.Position + lWritten;
  835. FOutputPending := FStream.Position < FStream.Size;
  836. FEof := not FOutputPending;
  837. Result := EofToWriteStatus[FEof];
  838. end;
  839. { TLHTTPSocket }
  840. constructor TLHTTPSocket.Create;
  841. begin
  842. inherited;
  843. FBuffer := GetMem(RequestBufferSize);
  844. FBufferSize := RequestBufferSize;
  845. FBufferPos := FBuffer;
  846. FBufferEnd := FBufferPos;
  847. FBuffer[0] := #0;
  848. FKeepAlive := true;
  849. end;
  850. destructor TLHTTPSocket.Destroy;
  851. begin
  852. FreeDelayFreeItems;
  853. inherited;
  854. FreeMem(FBuffer);
  855. end;
  856. procedure TLHTTPSocket.Disconnect(const Forced: Boolean = True);
  857. var
  858. lOutput: TOutputItem;
  859. begin
  860. inherited Disconnect(Forced);
  861. while FCurrentOutput <> nil do
  862. begin
  863. lOutput := FCurrentOutput;
  864. FCurrentOutput := FCurrentOutput.FNext;
  865. lOutput.Free;
  866. end;
  867. if FCurrentInput <> nil then
  868. FreeAndNil(FCurrentInput);
  869. end;
  870. procedure TLHTTPSocket.FreeDelayFreeItems;
  871. var
  872. lItem: TOutputItem;
  873. begin
  874. while FDelayFreeItems <> nil do
  875. begin
  876. lItem := FDelayFreeItems;
  877. FDelayFreeItems := FDelayFreeItems.FNextDelayFree;
  878. lItem.Free;
  879. end;
  880. end;
  881. procedure TLHTTPSocket.DelayFree(AOutputItem: TOutputItem);
  882. begin
  883. if AOutputItem = nil then exit;
  884. { check whether already in delayed free list }
  885. if AOutputItem = FDelayFreeItems then exit;
  886. if AOutputItem.FPrevDelayFree <> nil then exit;
  887. if FDelayFreeItems <> nil then
  888. FDelayFreeItems.FPrevDelayFree := AOutputItem;
  889. AOutputItem.FNextDelayFree := FDelayFreeItems;
  890. FDelayFreeItems := AOutputItem;
  891. end;
  892. procedure TLHTTPSocket.DoneBuffer(AOutput: TBufferOutput);
  893. begin
  894. end;
  895. procedure TLHTTPSocket.LogMessage;
  896. begin
  897. end;
  898. procedure TLHTTPSocket.LogAccess(const AMessage: string);
  899. begin
  900. end;
  901. procedure TLHTTPSocket.WriteError(AStatus: TLHTTPStatus);
  902. begin
  903. end;
  904. procedure TLHTTPSocket.AddToOutput(AOutputItem: TOutputItem);
  905. begin
  906. AOutputItem.FPrev := FLastOutput;
  907. if FLastOutput <> nil then
  908. begin
  909. FLastOutput.FNext := AOutputItem;
  910. end else begin
  911. FCurrentOutput := AOutputItem;
  912. end;
  913. FLastOutput := AOutputItem;
  914. end;
  915. procedure TLHTTPSocket.PrependOutput(ANewItem, AItem: TOutputItem);
  916. begin
  917. ANewItem.FPrev := AItem.FPrev;
  918. ANewItem.FNext := AItem;
  919. AItem.FPrev := ANewItem;
  920. if FCurrentOutput = AItem then
  921. FCurrentOutput := ANewItem;
  922. end;
  923. procedure TLHTTPSocket.RemoveOutput(AOutputItem: TOutputItem);
  924. begin
  925. if AOutputItem.FPrev <> nil then
  926. AOutputItem.FPrev.FNext := AOutputItem.FNext;
  927. if AOutputItem.FNext <> nil then
  928. AOutputItem.FNext.FPrev := AOutputItem.FPrev;
  929. if FLastOutput = AOutputItem then
  930. FLastOutput := AOutputItem.FPrev;
  931. if FCurrentOutput = AOutputItem then
  932. FCurrentOutput := AOutputItem.FNext;
  933. AOutputItem.FPrev := nil;
  934. AOutputItem.FNext := nil;
  935. end;
  936. procedure TLHTTPSocket.ResetDefaults;
  937. begin
  938. FParseBuffer := @ParseRequest;
  939. end;
  940. procedure TLHTTPSocket.FlushRequest;
  941. begin
  942. FillDWord(FParameters, sizeof(FParameters) div 4, 0);
  943. ResetDefaults;
  944. end;
  945. function TLHTTPSocket.CalcAvailableBufferSpace: integer;
  946. begin
  947. Result := FBufferSize-(FBufferEnd-FBuffer)-1;
  948. end;
  949. procedure TLHTTPSocket.HandleReceive;
  950. var
  951. lRead: integer;
  952. begin
  953. if FRequestInputDone then
  954. begin
  955. IgnoreRead := true;
  956. exit;
  957. end;
  958. lRead := CalcAvailableBufferSpace;
  959. { if buffer has filled up, keep ignoring and continue parsing requests }
  960. if lRead > 0 then
  961. begin
  962. IgnoreRead := false;
  963. lRead := Get(FBufferEnd^, lRead);
  964. if lRead = 0 then exit;
  965. Inc(FBufferEnd, lRead);
  966. FBufferEnd^ := #0;
  967. end;
  968. ParseBuffer;
  969. if FIgnoreWrite then
  970. WriteBlock;
  971. end;
  972. procedure TLHTTPSocket.RelocateVariable(var AVar: PAnsiChar);
  973. begin
  974. if AVar = nil then exit;
  975. AVar := FBuffer + (AVar - FRequestPos);
  976. end;
  977. procedure TLHTTPSocket.RelocateVariables;
  978. var
  979. I: TLHTTPParameter;
  980. begin
  981. for I := Low(TLHTTPParameter) to High(TLHTTPParameter) do
  982. RelocateVariable(FParameters[I]);
  983. end;
  984. procedure TLHTTPSocket.PackRequestBuffer;
  985. var
  986. lBytesLeft: integer;
  987. lFreeBuffer: PAnsiChar;
  988. begin
  989. if (FRequestBuffer <> nil) and (FBufferEnd-FBufferPos <= RequestBufferSize) then
  990. begin
  991. { switch back to normal size buffer }
  992. lFreeBuffer := FBuffer;
  993. FBuffer := FRequestBuffer;
  994. FBufferSize := RequestBufferSize;
  995. FRequestBuffer := nil;
  996. end else
  997. lFreeBuffer := nil;
  998. if FRequestPos <> nil then
  999. begin
  1000. lBytesLeft := FBufferEnd-FRequestPos;
  1001. FBufferEnd := FBuffer+lBytesLeft;
  1002. RelocateVariable(FBufferPos);
  1003. RelocateVariables;
  1004. { include null-terminator, where FBufferEnd is pointing at }
  1005. Move(FRequestPos^, FBuffer^, lBytesLeft+1);
  1006. FRequestPos := nil;
  1007. end;
  1008. if lFreeBuffer <> nil then
  1009. FreeMem(lFreeBuffer);
  1010. end;
  1011. procedure TLHTTPSocket.PackInputBuffer;
  1012. var
  1013. lBytesLeft: integer;
  1014. begin
  1015. { use bigger buffer for more speed }
  1016. if FRequestBuffer = nil then
  1017. begin
  1018. FRequestBuffer := FBuffer;
  1019. FBuffer := GetMem(DataBufferSize);
  1020. FBufferSize := DataBufferSize;
  1021. FRequestPos := nil;
  1022. end;
  1023. lBytesLeft := FBufferEnd-FBufferPos;
  1024. Move(FBufferPos^, FBuffer^, lBytesLeft);
  1025. FBufferEnd := FBuffer+lBytesLeft;
  1026. FBufferPos := FBuffer;
  1027. end;
  1028. function TLHTTPSocket.ParseEntityPlain: boolean;
  1029. var
  1030. lNumBytes: integer;
  1031. begin
  1032. lNumBytes := FBufferEnd - FBufferPos;
  1033. if lNumBytes > FInputRemaining then
  1034. lNumBytes := FInputRemaining;
  1035. { if no output item to feed into, discard }
  1036. if FCurrentInput <> nil then
  1037. lNumBytes := FCurrentInput.HandleInput(FBufferPos, lNumBytes);
  1038. inc(FBufferPos, lNumBytes);
  1039. dec(FInputRemaining, lNumBytes);
  1040. Result := FInputRemaining > 0;
  1041. { prepare for more data, if more data coming }
  1042. if Result and (FBufferPos+FInputRemaining > FBuffer+FBufferSize) then
  1043. PackInputBuffer;
  1044. end;
  1045. function TLHTTPSocket.ParseEntityChunked: boolean;
  1046. var
  1047. lLineEnd, lNextLine: PAnsiChar;
  1048. lCode: integer;
  1049. begin
  1050. repeat
  1051. if FChunkState = csFinished then
  1052. exit(false);
  1053. if FChunkState = csData then
  1054. if ParseEntityPlain then
  1055. exit(true)
  1056. else
  1057. FChunkState := csDataEnd;
  1058. lLineEnd := StrScan(FBufferPos, #10);
  1059. if lLineEnd = nil then
  1060. exit(true);
  1061. lNextLine := lLineEnd+1;
  1062. if (lLineEnd > FBufferPos) and ((lLineEnd-1)^ = #13) then
  1063. dec(lLineEnd);
  1064. case FChunkState of
  1065. csInitial:
  1066. begin
  1067. lLineEnd^ := #0;
  1068. HexToInt(FBufferPos, dword(FInputRemaining), lCode);
  1069. if lCode = 1 then
  1070. begin
  1071. FChunkState := csFinished;
  1072. Disconnect;
  1073. exit(false);
  1074. end;
  1075. if FInputRemaining = 0 then
  1076. FChunkState := csTrailer
  1077. else
  1078. FChunkState := csData;
  1079. end;
  1080. csDataEnd:
  1081. begin
  1082. { skip empty line }
  1083. FChunkState := csInitial;
  1084. end;
  1085. csTrailer:
  1086. begin
  1087. { trailer is optional, empty line indicates end }
  1088. if lLineEnd = FBufferPos then
  1089. FChunkState := csFinished
  1090. else
  1091. ParseParameterLine(lLineEnd);
  1092. end;
  1093. end;
  1094. FBufferPos := lNextLine;
  1095. until false;
  1096. end;
  1097. function TLHTTPSocket.ParseRequest: boolean;
  1098. var
  1099. pNextLine, pLineEnd: PAnsiChar;
  1100. begin
  1101. if FRequestHeaderDone then exit(not FRequestInputDone);
  1102. repeat
  1103. pLineEnd := StrScan(FBufferPos, #10);
  1104. if pLineEnd = nil then
  1105. begin
  1106. if (FRequestBuffer <> nil) or (FRequestPos <> nil) then
  1107. PackRequestBuffer
  1108. else if CalcAvailableBufferSpace = 0 then
  1109. WriteError(hsRequestTooLong);
  1110. exit(true);
  1111. end;
  1112. pNextLine := pLineEnd+1;
  1113. if (pLineEnd > FBufferPos) and ((pLineEnd-1)^ = #13) then
  1114. dec(pLineEnd);
  1115. pLineEnd^ := #0;
  1116. ParseLine(pLineEnd);
  1117. FBufferPos := pNextLine;
  1118. if FRequestHeaderDone then
  1119. exit(not FRequestInputDone);
  1120. until false;
  1121. end;
  1122. procedure TLHTTPSocket.ParseParameterLine(pLineEnd: PAnsiChar);
  1123. var
  1124. lPos: PAnsiChar;
  1125. I: TLHTTPParameter;
  1126. lLen: integer;
  1127. begin
  1128. lPos := StrScan(FBufferPos, ' ');
  1129. if (lPos = nil) or (lPos = FBufferPos) or ((lPos-1)^ <> ':') then
  1130. begin
  1131. WriteError(hsBadRequest);
  1132. exit;
  1133. end;
  1134. { null-terminate at colon }
  1135. (lPos-1)^ := #0;
  1136. StrUpper(FBufferPos);
  1137. lLen := lPos-FBufferPos-1;
  1138. for I := Low(TLHTTPParameter) to High(TLHTTPParameter) do
  1139. if (Length(HTTPParameterStrings[I]) = lLen)
  1140. and CompareMem(FBufferPos, PAnsiChar(HTTPParameterStrings[I]), lLen) then
  1141. begin
  1142. repeat
  1143. inc(lPos);
  1144. until lPos^ <> ' ';
  1145. FParameters[I] := lPos;
  1146. break;
  1147. end;
  1148. end;
  1149. procedure TLHTTPSocket.ParseLine(pLineEnd: PAnsiChar);
  1150. begin
  1151. if FBufferPos[0] = #0 then
  1152. begin
  1153. FRequestHeaderDone := true;
  1154. ProcessHeaders;
  1155. end else
  1156. ParseParameterLine(pLineEnd);
  1157. end;
  1158. function TLHTTPSocket.ParseBuffer: boolean;
  1159. var
  1160. lParseFunc: TParseBufferMethod;
  1161. begin
  1162. repeat
  1163. lParseFunc := FParseBuffer;
  1164. Result := FParseBuffer();
  1165. if not Result and not FRequestInputDone then
  1166. begin
  1167. FRequestInputDone := true;
  1168. if FCurrentInput <> nil then
  1169. FCurrentInput.DoneInput;
  1170. end;
  1171. { if parse func changed mid-run, then we should continue calling the new
  1172. one: header + data }
  1173. until (lParseFunc = FParseBuffer) or not Result;
  1174. end;
  1175. function TLHTTPSocket.ProcessEncoding: boolean;
  1176. var
  1177. lCode: integer;
  1178. lParam: PAnsiChar;
  1179. begin
  1180. Result := true;
  1181. lParam := FParameters[hpContentLength];
  1182. if lParam <> nil then
  1183. begin
  1184. FParseBuffer := @ParseEntityPlain;
  1185. Val(lParam, FInputRemaining, lCode);
  1186. if lCode <> 0 then
  1187. WriteError(hsBadRequest);
  1188. exit;
  1189. end;
  1190. lParam := FParameters[hpTransferEncoding];
  1191. if lParam <> nil then
  1192. begin
  1193. if StrIComp(lParam, 'chunked') = 0 then
  1194. begin
  1195. FParseBuffer := @ParseEntityChunked;
  1196. FChunkState := csInitial;
  1197. end else
  1198. Result := false;
  1199. exit;
  1200. end;
  1201. { only if keep-alive, then user must specify either of above headers to
  1202. indicate next header's start }
  1203. lParam := FParameters[hpConnection];
  1204. FRequestInputDone := (lParam <> nil) and (StrIComp(lParam, 'keep-alive') = 0);
  1205. if not FRequestInputDone then
  1206. begin
  1207. FParseBuffer := @ParseEntityPlain;
  1208. FInputRemaining := high(FInputRemaining);
  1209. end;
  1210. end;
  1211. function TLHTTPSocket.SetupEncoding(AOutputItem: TBufferOutput; AHeaderOut: PHeaderOutInfo): boolean;
  1212. begin
  1213. if AHeaderOut^.ContentLength = 0 then
  1214. begin
  1215. if AHeaderOut^.Version >= 11 then
  1216. begin
  1217. { we can use chunked encoding }
  1218. AHeaderOut^.TransferEncoding := teChunked;
  1219. AOutputItem.SelectChunked;
  1220. end else begin
  1221. { we need to buffer the response to find its length }
  1222. AHeaderOut^.TransferEncoding := teIdentity;
  1223. AOutputItem.SelectBuffered;
  1224. { need to accumulate data before starting header output }
  1225. AddToOutput(AOutputItem);
  1226. exit(false);
  1227. end;
  1228. end else begin
  1229. AHeaderOut^.TransferEncoding := teIdentity;
  1230. AOutputItem.SelectPlain;
  1231. end;
  1232. Result := true;
  1233. end;
  1234. procedure TLHTTPSocket.WriteBlock;
  1235. begin
  1236. while true do
  1237. begin
  1238. if FCurrentOutput = nil then
  1239. begin
  1240. if not FOutputDone or (not FRequestInputDone and FKeepAlive) then
  1241. break;
  1242. if not FKeepAlive then
  1243. begin
  1244. Disconnect;
  1245. exit;
  1246. end;
  1247. { next request }
  1248. FRequestInputDone := false;
  1249. FRequestHeaderDone := false;
  1250. FOutputDone := false;
  1251. FRequestPos := FBufferPos;
  1252. FlushRequest;
  1253. { rewind buffer pointers if at end of buffer anyway }
  1254. if FBufferPos = FBufferEnd then
  1255. PackRequestBuffer;
  1256. if ParseBuffer and IgnoreRead then
  1257. begin
  1258. { end of input buffer reached, try reading more }
  1259. HandleReceive;
  1260. end;
  1261. if FCurrentOutput = nil then
  1262. break;
  1263. end;
  1264. { if we cannot send, then the send buffer is full }
  1265. if (FConnectionStatus <> scConnected) or not (ssCanSend in FSocketState) then
  1266. break;
  1267. case FCurrentOutput.WriteBlock of
  1268. wsDone:
  1269. begin
  1270. if FCurrentOutput = FLastOutput then
  1271. FLastOutput := nil;
  1272. { some output items may trigger this parse/write loop }
  1273. DelayFree(FCurrentOutput);
  1274. FCurrentOutput := FCurrentOutput.FNext;
  1275. end;
  1276. wsWaitingData:
  1277. begin
  1278. { wait for more data from external source }
  1279. break;
  1280. end;
  1281. end;
  1282. { nothing left to write, request was busy and now completed }
  1283. if FCurrentOutput = nil then
  1284. begin
  1285. LogMessage;
  1286. FOutputDone := true;
  1287. end;
  1288. end;
  1289. end;
  1290. { TLHTTPServerSocket }
  1291. constructor TLHTTPServerSocket.Create;
  1292. begin
  1293. inherited;
  1294. FLogMessage := InitStringBuffer(256);
  1295. FHeaderOut.ExtraHeaders := InitStringBuffer(256);
  1296. ResetDefaults;
  1297. end;
  1298. destructor TLHTTPServerSocket.Destroy;
  1299. begin
  1300. FreeMem(FLogMessage.Memory);
  1301. FreeMem(FHeaderOut.ExtraHeaders.Memory);
  1302. inherited;
  1303. end;
  1304. procedure TLHTTPServerSocket.AddContentLength(ALength: integer);
  1305. begin
  1306. Inc(FHeaderOut.ContentLength, ALength);
  1307. end;
  1308. procedure TLHTTPServerSocket.DoneBuffer(AOutput: TBufferOutput);
  1309. begin
  1310. if FCurrentOutput <> AOutput then
  1311. begin
  1312. RemoveOutput(AOutput);
  1313. AOutput.FNext := FCurrentOutput;
  1314. FCurrentOutput := AOutput;
  1315. end;
  1316. WriteHeaders(AOutput, nil);
  1317. end;
  1318. procedure TLHTTPServerSocket.LogAccess(const AMessage: string);
  1319. begin
  1320. TLHTTPConnection(FCreator).LogAccess(AMessage);
  1321. end;
  1322. procedure TLHTTPServerSocket.LogMessage;
  1323. begin
  1324. { log a message about this request,
  1325. '<StatusCode> <Length> "<Referer>" "<User-Agent>"' }
  1326. AppendString(FLogMessage, IntToStr(HTTPStatusCodes[FResponseInfo.Status]));
  1327. AppendChar(FLogMessage, ' ');
  1328. AppendString(FLogMessage, IntToStr(FHeaderOut.ContentLength));
  1329. AppendString(FLogMessage, ' "');
  1330. AppendString(FLogMessage, FParameters[hpReferer]);
  1331. AppendString(FLogMessage, AnsiString('" "'));
  1332. AppendString(FLogMessage, FParameters[hpUserAgent]);
  1333. AppendChar(FLogMessage, '"');
  1334. AppendChar(FLogMessage, #0);
  1335. LogAccess(FLogMessage.Memory);
  1336. end;
  1337. procedure TLHTTPServerSocket.ResetDefaults;
  1338. begin
  1339. inherited;
  1340. FRequestInfo.RequestType := hmUnknown;
  1341. FSetupEncodingState := seNone;
  1342. with FResponseInfo do
  1343. begin
  1344. Status := hsOK;
  1345. ContentType := 'application/octet-stream';
  1346. ContentCharset := '';
  1347. LastModified := 0.0;
  1348. end;
  1349. end;
  1350. procedure TLHTTPServerSocket.FlushRequest;
  1351. { reset structure to zero, not called from constructor }
  1352. begin
  1353. with FRequestInfo do
  1354. begin
  1355. { request }
  1356. Argument := nil;
  1357. QueryParams := nil;
  1358. Version := 0;
  1359. end;
  1360. with FHeaderOut do
  1361. begin
  1362. ContentLength := 0;
  1363. TransferEncoding := teIdentity;
  1364. ExtraHeaders.Pos := ExtraHeaders.Memory;
  1365. Version := 0;
  1366. end;
  1367. inherited;
  1368. end;
  1369. procedure TLHTTPServerSocket.RelocateVariables;
  1370. begin
  1371. RelocateVariable(FRequestInfo.Method);
  1372. RelocateVariable(FRequestInfo.Argument);
  1373. RelocateVariable(FRequestInfo.QueryParams);
  1374. RelocateVariable(FRequestInfo.VersionStr);
  1375. inherited;
  1376. end;
  1377. procedure TLHTTPServerSocket.ParseLine(pLineEnd: PAnsiChar);
  1378. begin
  1379. if FRequestInfo.RequestType = hmUnknown then
  1380. begin
  1381. ParseRequestLine(pLineEnd);
  1382. exit;
  1383. end;
  1384. inherited;
  1385. end;
  1386. procedure TLHTTPServerSocket.ParseRequestLine(pLineEnd: PAnsiChar);
  1387. var
  1388. lPos: PAnsiChar;
  1389. I: TLHTTPMethod;
  1390. NowLocal: TDateTime;
  1391. begin
  1392. { make a timestamp for this request }
  1393. NowLocal := Now;
  1394. FRequestInfo.DateTime := LocalTimeToGMT(NowLocal);
  1395. { begin log message }
  1396. FLogMessage.Pos := FLogMessage.Memory;
  1397. AppendString(FLogMessage, PeerAddress);
  1398. AppendString(FLogMessage, ' - [');
  1399. AppendString(FLogMessage, FormatDateTime('dd/mmm/yyyy:hh:nn:ss', NowLocal));
  1400. AppendString(FLogMessage, TLHTTPServer(FCreator).FLogMessageTZString);
  1401. AppendString(FLogMessage, FBufferPos, pLineEnd-FBufferPos);
  1402. AppendString(FLogMessage, '" ');
  1403. { decode version }
  1404. lPos := pLineEnd;
  1405. repeat
  1406. if lPos^ = ' ' then break;
  1407. dec(lPos);
  1408. if lPos < FBufferPos then
  1409. begin
  1410. WriteError(hsBadRequest);
  1411. exit;
  1412. end;
  1413. until false;
  1414. lPos^ := #0;
  1415. inc(lPos);
  1416. { lPos = version string }
  1417. if not HTTPVersionCheck(lPos, pLineEnd, FRequestInfo.Version) then
  1418. begin
  1419. WriteError(hsBadRequest);
  1420. exit;
  1421. end;
  1422. FRequestInfo.VersionStr := lPos;
  1423. FHeaderOut.Version := FRequestInfo.Version;
  1424. { trim spaces at end of URI }
  1425. dec(lPos);
  1426. repeat
  1427. if lPos = FBufferPos then break;
  1428. dec(lPos);
  1429. if lPos^ <> ' ' then break;
  1430. lPos^ := #0;
  1431. until false;
  1432. { decode method }
  1433. FRequestInfo.Method := FBufferPos;
  1434. lPos := StrScan(FBufferPos, ' ');
  1435. if lPos = nil then
  1436. begin
  1437. WriteError(hsBadRequest);
  1438. exit;
  1439. end;
  1440. lPos^ := #0;
  1441. for I := Low(TLHTTPMethod) to High(TLHTTPMethod) do
  1442. begin
  1443. if (I = hmUnknown) or (((lPos-FBufferPos) = Length(HTTPMethodStrings[I]))
  1444. and CompareMem(FBufferPos, PAnsiChar(HTTPMethodStrings[I]), lPos-FBufferPos)) then
  1445. begin
  1446. repeat
  1447. inc(lPos);
  1448. until lPos^ <> ' ';
  1449. FRequestInfo.Argument := lPos;
  1450. FRequestInfo.RequestType := I;
  1451. break;
  1452. end;
  1453. end;
  1454. if ((pLineEnd-FRequestInfo.Argument) > 7) and (StrIComp(FRequestInfo.Argument, 'http://') = 0) then
  1455. begin
  1456. { absolute URI }
  1457. lPos := FRequestInfo.Argument+7;
  1458. while (lPos^ = '/') do
  1459. Inc(lPos);
  1460. FParameters[hpHost] := lPos;
  1461. lPos := StrScan(lPos, '/');
  1462. FRequestInfo.Argument := lPos;
  1463. end;
  1464. { FRequestInfo.Argument now points to an "abs_path" }
  1465. if FRequestInfo.Argument[0] <> '/' then
  1466. begin
  1467. WriteError(hsBadRequest);
  1468. exit;
  1469. end;
  1470. repeat
  1471. Inc(FRequestInfo.Argument);
  1472. until FRequestInfo.Argument[0] <> '/';
  1473. end;
  1474. procedure TLHTTPServerSocket.ProcessHeaders;
  1475. { process request }
  1476. var
  1477. lPos, lConnParam: PAnsiChar;
  1478. begin
  1479. { do HTTP/1.1 Host-field present check }
  1480. if (FRequestInfo.Version > 10) and (FParameters[hpHost] = nil) then
  1481. begin
  1482. WriteError(hsBadRequest);
  1483. exit;
  1484. end;
  1485. lPos := StrScan(FRequestInfo.Argument, '?');
  1486. if lPos <> nil then
  1487. begin
  1488. lPos^ := #0;
  1489. FRequestInfo.QueryParams := lPos+1;
  1490. end;
  1491. FKeepAlive := FRequestInfo.Version > 10;
  1492. lConnParam := FParameters[hpConnection];
  1493. if lConnParam <> nil then
  1494. begin
  1495. if StrIComp(lConnParam, 'keep-alive') = 0 then
  1496. FKeepAlive := true
  1497. else
  1498. if StrIComp(lConnParam, 'close') = 0 then
  1499. FKeepAlive := false;
  1500. end;
  1501. HTTPDecode(FRequestInfo.Argument);
  1502. if not CheckPermission(FRequestInfo.Argument) then
  1503. begin
  1504. WriteError(hsForbidden);
  1505. end else begin
  1506. if not ProcessEncoding then
  1507. begin
  1508. WriteError(hsNotImplemented);
  1509. exit;
  1510. end;
  1511. FCurrentInput := HandleURI;
  1512. { if we have a valid outputitem, wait until it is ready
  1513. to produce its response }
  1514. if FCurrentInput = nil then
  1515. begin
  1516. if FResponseInfo.Status = hsOK then
  1517. WriteError(hsNotFound)
  1518. else
  1519. WriteError(FResponseInfo.Status);
  1520. end else if FRequestInputDone then
  1521. FCurrentInput.DoneInput;
  1522. end;
  1523. end;
  1524. function TLHTTPServerSocket.PrepareResponse(AOutputItem: TOutputItem; ACustomErrorMessage: boolean): boolean;
  1525. var
  1526. lDateTime: TDateTime;
  1527. begin
  1528. { check modification date }
  1529. if FResponseInfo.Status < hsBadRequest then
  1530. begin
  1531. if (FParameters[hpIfModifiedSince] <> nil)
  1532. and (FResponseInfo.LastModified <> 0.0) then
  1533. begin
  1534. if TryHTTPDateStrToDateTime(FParameters[hpIfModifiedSince], lDateTime) then
  1535. begin
  1536. if lDateTime > FRequestInfo.DateTime then
  1537. FResponseInfo.Status := hsBadRequest
  1538. else
  1539. if FResponseInfo.LastModified <= lDateTime then
  1540. FResponseInfo.Status := hsNotModified;
  1541. end;
  1542. end else
  1543. if (FParameters[hpIfUnmodifiedSince] <> nil) then
  1544. begin
  1545. if TryHTTPDateStrToDateTime(FParameters[hpIfUnmodifiedSince], lDateTime) then
  1546. begin
  1547. if (FResponseInfo.LastModified = 0.0)
  1548. or (lDateTime < FResponseInfo.LastModified) then
  1549. FResponseInfo.Status := hsPreconditionFailed;
  1550. end;
  1551. end;
  1552. end;
  1553. if (FResponseInfo.Status < hsOK) or (FResponseInfo.Status in [hsNoContent, hsNotModified]) then
  1554. begin
  1555. { RFC says we MUST not include a response for these statuses }
  1556. ACustomErrorMessage := false;
  1557. FHeaderOut.ContentLength := 0;
  1558. end;
  1559. Result := (FResponseInfo.Status = hsOK) or ACustomErrorMessage;
  1560. if not Result then
  1561. begin
  1562. WriteError(FResponseInfo.Status);
  1563. DelayFree(AOutputItem);
  1564. end;
  1565. end;
  1566. procedure TLHTTPServerSocket.StartMemoryResponse(AOutputItem: TMemoryOutput; ACustomErrorMessage: boolean = false);
  1567. begin
  1568. if PrepareResponse(AOutputItem, ACustomErrorMessage) then
  1569. begin
  1570. if FRequestInfo.RequestType <> hmHead then
  1571. FHeaderOut.ContentLength := AOutputItem.FBufferSize
  1572. else
  1573. FHeaderOut.ContentLength := 0;
  1574. WriteHeaders(nil, AOutputItem);
  1575. end;
  1576. end;
  1577. function TLHTTPServerSocket.SetupEncoding(AOutputItem: TBufferOutput): boolean;
  1578. const
  1579. SetupEncodingToState: array[boolean] of TSetupEncodingState = (seWaitHeaders, seStartHeaders);
  1580. begin
  1581. if FSetupEncodingState > seNone then
  1582. exit(FSetupEncodingState = seStartHeaders);
  1583. Result := inherited SetupEncoding(AOutputItem, @FHeaderOut);
  1584. FSetupEncodingState := SetupEncodingToState[Result];
  1585. end;
  1586. procedure TLHTTPServerSocket.StartResponse(AOutputItem: TBufferOutput; ACustomErrorMessage: boolean = false);
  1587. begin
  1588. if PrepareResponse(AOutputItem, ACustomErrorMessage) then
  1589. if (FRequestInfo.RequestType = hmHead) or SetupEncoding(AOutputItem) then
  1590. WriteHeaders(nil, AOutputItem);
  1591. end;
  1592. function TLHTTPServerSocket.HandleURI: TOutputItem; {inline;} {<--- triggers IE}
  1593. begin
  1594. Result := TLHTTPServer(FCreator).HandleURI(Self);
  1595. end;
  1596. procedure TLHTTPServerSocket.WriteError(AStatus: TLHTTPStatus);
  1597. var
  1598. lMessage: string;
  1599. lMsgOutput: TMemoryOutput;
  1600. begin
  1601. if AStatus in HTTPDisconnectStatuses then
  1602. FKeepAlive := false;
  1603. lMessage := HTTPDescriptions[AStatus];
  1604. FRequestHeaderDone := true;
  1605. FResponseInfo.Status := AStatus;
  1606. FHeaderOut.ContentLength := Length(lMessage);
  1607. FHeaderOut.TransferEncoding := teIdentity;
  1608. if Length(lMessage) > 0 then
  1609. begin
  1610. FResponseInfo.ContentType := 'text/html';
  1611. lMsgOutput := TMemoryOutput.Create(Self, PAnsiChar(lMessage), 0, Length(lMessage), false)
  1612. end else begin
  1613. FResponseInfo.ContentType := '';
  1614. lMsgOutput := nil;
  1615. end;
  1616. WriteHeaders(nil, lMsgOutput);
  1617. end;
  1618. procedure TLHTTPServerSocket.WriteHeaders(AHeaderResponse, ADataResponse: TOutputItem);
  1619. var
  1620. lTemp: string[23];
  1621. lMessage: TStringBuffer;
  1622. tempStr: string;
  1623. begin
  1624. lMessage := InitStringBuffer(504);
  1625. AppendString(lMessage, 'HTTP/1.1 ');
  1626. Str(HTTPStatusCodes[FResponseInfo.Status], lTemp);
  1627. AppendString(lMessage, lTemp);
  1628. AppendChar(lMessage, ' ');
  1629. AppendString(lMessage, HTTPTexts[FResponseInfo.Status]);
  1630. AppendString(lMessage, #13#10+'Date: ');
  1631. AppendString(lMessage, FormatDateTime(HTTPDateFormat, FRequestInfo.DateTime));
  1632. AppendString(lMessage, ' GMT');
  1633. tempStr := TLHTTPServer(FCreator).ServerSoftware;
  1634. if Length(tempStr) > 0 then
  1635. begin
  1636. AppendString(lMessage, #13#10+'Server: ');
  1637. AppendString(lMessage, tempStr);
  1638. end;
  1639. if Length(FResponseInfo.ContentType) > 0 then
  1640. begin
  1641. AppendString(lMessage, #13#10+'Content-Type: ');
  1642. AppendString(lMessage, FResponseInfo.ContentType);
  1643. if Length(FResponseInfo.ContentCharset) > 0 then
  1644. begin
  1645. AppendString(lMessage, '; charset=');
  1646. AppendString(lMessage, FResponseInfo.ContentCharset);
  1647. end;
  1648. end;
  1649. if FHeaderOut.TransferEncoding = teIdentity then
  1650. begin
  1651. AppendString(lMessage, #13#10+'Content-Length: ');
  1652. Str(FHeaderOut.ContentLength, lTemp);
  1653. AppendString(lMessage, lTemp);
  1654. end else begin
  1655. { only other possibility: teChunked }
  1656. AppendString(lMessage, #13#10+'Transfer-Encoding: chunked');
  1657. end;
  1658. if FResponseInfo.LastModified <> 0.0 then
  1659. begin
  1660. AppendString(lMessage, #13#10+'Last-Modified: ');
  1661. AppendString(lMessage, FormatDateTime(HTTPDateFormat, FResponseInfo.LastModified));
  1662. AppendString(lMessage, ' GMT');
  1663. end;
  1664. AppendString(lMessage, #13#10+'Connection: ');
  1665. if FKeepAlive then
  1666. AppendString(lMessage, 'keep-alive')
  1667. else
  1668. AppendString(lMessage, 'close');
  1669. AppendString(lMessage, #13#10);
  1670. with FHeaderOut.ExtraHeaders do
  1671. AppendString(lMessage, Memory, Pos-Memory);
  1672. AppendString(lMessage, #13#10);
  1673. if AHeaderResponse <> nil then
  1674. begin
  1675. AHeaderResponse.FBuffer := lMessage.Memory;
  1676. AHeaderResponse.FBufferSize := lMessage.Pos-lMessage.Memory;
  1677. end else
  1678. AddToOutput(TMemoryOutput.Create(Self, lMessage.Memory, 0,
  1679. lMessage.Pos-lMessage.Memory, true));
  1680. if ADataResponse <> nil then
  1681. begin
  1682. if FRequestInfo.RequestType = hmHead then
  1683. DelayFree(ADataResponse)
  1684. else
  1685. AddToOutput(ADataResponse);
  1686. end;
  1687. end;
  1688. { TLHTTPConnection }
  1689. destructor TLHTTPConnection.Destroy;
  1690. begin
  1691. inherited;
  1692. end;
  1693. procedure TLHTTPConnection.LogAccess(const AMessage: string);
  1694. begin
  1695. end;
  1696. procedure TLHTTPConnection.ReceiveEvent(aSocket: TLHandle);
  1697. begin
  1698. TLHTTPSocket(aSocket).HandleReceive;
  1699. TLHTTPSocket(aSocket).FreeDelayFreeItems;
  1700. end;
  1701. procedure TLHTTPConnection.CanSendEvent(aSocket: TLHandle);
  1702. begin
  1703. TLHTTPSocket(aSocket).WriteBlock;
  1704. TLHTTPSocket(aSocket).FreeDelayFreeItems;
  1705. end;
  1706. { TLHTTPServer }
  1707. constructor TLHTTPServer.Create(AOwner: TComponent);
  1708. var
  1709. TZSign: char;
  1710. TZSecsAbs: integer;
  1711. begin
  1712. inherited Create(AOwner);
  1713. FPort := 80; // default port
  1714. SocketClass := TLHTTPServerSocket;
  1715. if TZSeconds >= 0 then
  1716. TZSign := '+'
  1717. else
  1718. TZSign := '-';
  1719. TZSecsAbs := Abs(TZSeconds);
  1720. FLogMessageTZString := Format(' %s%.2d%.2d] "',
  1721. [TZSign, TZSecsAbs div 3600, (TZSecsAbs div 60) mod 60]);
  1722. end;
  1723. function TLHTTPServer.HandleURI(ASocket: TLHTTPServerSocket): TOutputItem;
  1724. var
  1725. lHandler: TURIHandler;
  1726. begin
  1727. Result := nil;
  1728. lHandler := FHandlerList;
  1729. while lHandler <> nil do
  1730. begin
  1731. if ASocket.FRequestInfo.RequestType in lHandler.Methods then
  1732. begin
  1733. Result := lHandler.HandleURI(ASocket);
  1734. if ASocket.FResponseInfo.Status <> hsOK then break;
  1735. if Result <> nil then break;
  1736. end;
  1737. lHandler := lHandler.FNext;
  1738. end;
  1739. end;
  1740. procedure TLHTTPServer.LogAccess(const AMessage: string);
  1741. begin
  1742. if Assigned(FOnAccess) then
  1743. FOnAccess(AMessage);
  1744. end;
  1745. procedure TLHTTPServer.RegisterHandler(AHandler: TURIHandler);
  1746. begin
  1747. if AHandler = nil then exit;
  1748. AHandler.FNext := FHandlerList;
  1749. FHandlerList := AHandler;
  1750. if Eventer <> nil then
  1751. AHandler.RegisterWithEventer(Eventer);
  1752. end;
  1753. procedure TLHTTPServer.RegisterWithEventer;
  1754. var
  1755. lHandler: TURIHandler;
  1756. begin
  1757. inherited;
  1758. lHandler := FHandlerList;
  1759. while lHandler <> nil do
  1760. begin
  1761. lHandler.RegisterWithEventer(Eventer);
  1762. lHandler := lHandler.FNext;
  1763. end;
  1764. end;
  1765. { TClientInput }
  1766. type
  1767. TClientOutput = class(TOutputItem)
  1768. protected
  1769. FPersistent: boolean;
  1770. procedure DoneInput; override;
  1771. public
  1772. constructor Create(ASocket: TLHTTPClientSocket);
  1773. destructor Destroy; override;
  1774. procedure FreeInstance; override;
  1775. function HandleInput(ABuffer: PAnsiChar; ASize: integer): integer; override;
  1776. function WriteBlock: TWriteBlockStatus; override;
  1777. end;
  1778. constructor TClientOutput.Create(ASocket: TLHTTPClientSocket);
  1779. begin
  1780. inherited Create(ASocket);
  1781. FPersistent := true;
  1782. end;
  1783. destructor TClientOutput.Destroy;
  1784. begin
  1785. if FPersistent then exit;
  1786. inherited;
  1787. end;
  1788. procedure TClientOutput.FreeInstance;
  1789. begin
  1790. if FPersistent then exit;
  1791. inherited;
  1792. end;
  1793. procedure TClientOutput.DoneInput;
  1794. begin
  1795. TLHTTPClient(TLHTTPClientSocket(FSocket).FCreator).
  1796. DoDoneInput(TLHTTPClientSocket(FSocket));
  1797. end;
  1798. function TClientOutput.HandleInput(ABuffer: PAnsiChar; ASize: integer): integer;
  1799. begin
  1800. Result := TLHTTPClient(TLHTTPClientSocket(FSocket).FCreator).
  1801. DoHandleInput(TLHTTPClientSocket(FSocket), ABuffer, ASize);
  1802. end;
  1803. function TClientOutput.WriteBlock: TWriteBlockStatus;
  1804. begin
  1805. Result := TLHTTPClient(TLHTTPClientSocket(FSocket).FCreator).
  1806. DoWriteBlock(TLHTTPClientSocket(FSocket));
  1807. end;
  1808. { TLHTTPClientSocket }
  1809. constructor TLHTTPClientSocket.Create;
  1810. begin
  1811. inherited Create;
  1812. FCurrentInput := TClientOutput.Create(Self);
  1813. ResetDefaults;
  1814. end;
  1815. destructor TLHTTPClientSocket.Destroy;
  1816. begin
  1817. if Assigned(FCurrentInput) then begin
  1818. TClientOutput(FCurrentInput).FPersistent := false;
  1819. FreeAndNil(FCurrentInput);
  1820. end;
  1821. inherited;
  1822. end;
  1823. procedure TLHTTPClientSocket.AddContentLength(ALength: integer);
  1824. begin
  1825. Inc(TLHTTPClient(FCreator).FHeaderOut.ContentLength, ALength);
  1826. end;
  1827. procedure TLHTTPClientSocket.Cancel(AError: TLHTTPClientError);
  1828. begin
  1829. FError := AError;
  1830. Disconnect;
  1831. end;
  1832. function TLHTTPClientSocket.GetResponseReason: string;
  1833. begin
  1834. Result := FResponse^.Reason;
  1835. end;
  1836. function TLHTTPClientSocket.GetResponseStatus: TLHTTPStatus;
  1837. begin
  1838. Result := FResponse^.Status;
  1839. end;
  1840. procedure TLHTTPClientSocket.SendRequest;
  1841. var
  1842. lMessage: TStringBuffer;
  1843. lTemp: string[23];
  1844. hasRangeStart, hasRangeEnd: boolean;
  1845. begin
  1846. lMessage := InitStringBuffer(504);
  1847. AppendString(lMessage, HTTPMethodStrings[FRequest^.Method]);
  1848. AppendChar(lMessage, ' ');
  1849. AppendString(lMessage, FRequest^.URI);
  1850. AppendChar(lMessage, ' ');
  1851. AppendString(lMessage, 'HTTP/1.1'+#13#10+'Host: ');
  1852. AppendString(lMessage, TLHTTPClient(FCreator).Host);
  1853. if TLHTTPClient(FCreator).Port <> 80 then
  1854. begin
  1855. AppendChar(lMessage, ':');
  1856. Str(TLHTTPClient(FCreator).Port, lTemp);
  1857. AppendString(lMessage, lTemp);
  1858. end;
  1859. AppendString(lMessage, #13#10);
  1860. if FHeaderOut^.ContentLength > 0 then
  1861. begin
  1862. AppendString(lMessage, 'Content-Length: ');
  1863. Str(FHeaderOut^.ContentLength, lTemp);
  1864. AppendString(lMessage, lTemp+#13#10);
  1865. end;
  1866. hasRangeStart := TLHTTPClient(FCreator).RangeStart <> high(qword);
  1867. hasRangeEnd := TLHTTPClient(FCreator).RangeEnd <> high(qword);
  1868. if hasRangeStart or hasRangeEnd then
  1869. begin
  1870. AppendString(lMessage, 'Range: bytes=');
  1871. if hasRangeStart then
  1872. begin
  1873. Str(TLHTTPClient(FCreator).RangeStart, lTemp);
  1874. AppendString(lMessage, lTemp);
  1875. end;
  1876. AppendChar(lMessage, '-');
  1877. if hasRangeEnd then
  1878. begin
  1879. Str(TLHTTPClient(FCreator).RangeEnd, lTemp);
  1880. AppendString(lMessage, lTemp);
  1881. end;
  1882. AppendString(lMessage, #13#10);
  1883. end;
  1884. with FHeaderOut^.ExtraHeaders do
  1885. AppendString(lMessage, Memory, Pos-Memory);
  1886. AppendString(lMessage, #13#10);
  1887. AddToOutput(TMemoryOutput.Create(Self, lMessage.Memory, 0,
  1888. lMessage.Pos-lMessage.Memory, true));
  1889. AddToOutput(FCurrentInput);
  1890. WriteBlock;
  1891. end;
  1892. procedure TLHTTPClientSocket.ParseLine(pLineEnd: PAnsiChar);
  1893. begin
  1894. if FError <> ceNone then
  1895. exit;
  1896. if FResponse^.Status = hsUnknown then
  1897. begin
  1898. ParseStatusLine(pLineEnd);
  1899. exit;
  1900. end;
  1901. inherited;
  1902. end;
  1903. procedure TLHTTPClientSocket.ParseStatusLine(pLineEnd: PAnsiChar);
  1904. var
  1905. lPos: PAnsiChar;
  1906. begin
  1907. lPos := FBufferPos;
  1908. repeat
  1909. if lPos >= pLineEnd then
  1910. begin
  1911. Cancel(ceMalformedStatusLine);
  1912. exit;
  1913. end;
  1914. if lPos^ = ' ' then
  1915. break;
  1916. Inc(lPos);
  1917. until false;
  1918. if not HTTPVersionCheck(FBufferPos, lPos, FResponse^.Version) then
  1919. begin
  1920. Cancel(ceMalformedStatusLine);
  1921. exit;
  1922. end;
  1923. if (FResponse^.Version > 11) then
  1924. begin
  1925. Cancel(ceVersionNotSupported);
  1926. exit;
  1927. end;
  1928. { status code }
  1929. Inc(lPos);
  1930. if (lPos+3 >= pLineEnd) or (lPos[3] <> ' ') then
  1931. begin
  1932. Cancel(ceMalformedStatusLine);
  1933. exit;
  1934. end;
  1935. FResponse^.Status := CodeToHTTPStatus((ord(lPos[0])-ord('0'))*100
  1936. + (ord(lPos[1])-ord('0'))*10 + (ord(lPos[2])-ord('0')));
  1937. if FResponse^.Status = hsUnknown then
  1938. begin
  1939. Cancel(ceMalformedStatusLine);
  1940. exit;
  1941. end;
  1942. Inc(lPos, 4);
  1943. if lPos < pLineEnd then
  1944. FResponse^.Reason := lPos;
  1945. end;
  1946. procedure TLHTTPClientSocket.ProcessHeaders;
  1947. begin
  1948. if not ProcessEncoding then
  1949. Cancel(ceUnsupportedEncoding);
  1950. TLHTTPClient(FCreator).DoProcessHeaders(Self);
  1951. end;
  1952. procedure TLHTTPClientSocket.ResetDefaults;
  1953. begin
  1954. inherited;
  1955. FError := ceNone;
  1956. end;
  1957. { TLHTTPClient }
  1958. constructor TLHTTPClient.Create(AOwner: TComponent);
  1959. begin
  1960. inherited;
  1961. FPort := 80;
  1962. SocketClass := TLHTTPClientSocket;
  1963. FRequest.Method := hmGet;
  1964. FHeaderOut.ExtraHeaders := InitStringBuffer(256);
  1965. ResetRange;
  1966. end;
  1967. destructor TLHTTPClient.Destroy;
  1968. begin
  1969. FreeMem(FHeaderOut.ExtraHeaders.Memory);
  1970. inherited;
  1971. end;
  1972. procedure TLHTTPClient.AddExtraHeader(const AHeader: string);
  1973. begin
  1974. AppendString(FHeaderOut.ExtraHeaders, AHeader);
  1975. AppendString(FHeaderOut.ExtraHeaders, #13#10);
  1976. end;
  1977. procedure TLHTTPClient.AddCookie(const AName, AValue: string; const APath: string = '';
  1978. const ADomain: string = ''; const AVersion: string = '0');
  1979. var
  1980. lHeader: string;
  1981. begin
  1982. lHeader := 'Cookie: $Version='+AVersion+'; '+AName+'='+EscapeCookie(AValue);
  1983. if Length(APath) > 0 then
  1984. lHeader := lHeader+';$Path='+APath;
  1985. if Length(ADomain) > 0 then
  1986. lHeader := lHeader+';$Domain='+ADomain;
  1987. AddExtraHeader(lHeader);
  1988. end;
  1989. procedure TLHTTPClient.ConnectEvent(aSocket: TLHandle);
  1990. begin
  1991. inherited;
  1992. InternalSendRequest;
  1993. end;
  1994. procedure TLHTTPClient.DoDoneInput(ASocket: TLHTTPClientSocket);
  1995. begin
  1996. Dec(FPendingResponses);
  1997. if FPendingResponses = 0 then
  1998. FState := hcsIdle
  1999. else
  2000. FState := hcsWaiting;
  2001. if Assigned(FOnDoneInput) then
  2002. FOnDoneInput(ASocket);
  2003. end;
  2004. function TLHTTPClient.DoHandleInput(ASocket: TLHTTPClientSocket; ABuffer: PAnsiChar; ASize: integer): integer;
  2005. begin
  2006. FState := hcsReceiving;
  2007. if Assigned(FOnInput) then
  2008. Result := FOnInput(ASocket, ABuffer, ASize)
  2009. else
  2010. Result := ASize;
  2011. end;
  2012. procedure TLHTTPClient.DoProcessHeaders(ASocket: TLHTTPClientSocket);
  2013. begin
  2014. if Assigned(FOnProcessHeaders) then
  2015. FOnProcessHeaders(ASocket);
  2016. end;
  2017. function TLHTTPClient.DoWriteBlock(ASocket: TLHTTPClientSocket): TWriteBlockStatus;
  2018. begin
  2019. Result := wsDone;
  2020. if not FOutputEof then
  2021. if Assigned(FOnCanWrite) then
  2022. FOnCanWrite(ASocket, Result)
  2023. end;
  2024. function TLHTTPClient.InitSocket(aSocket: TLSocket): TLSocket;
  2025. begin
  2026. TLHTTPClientSocket(aSocket).FHeaderOut := @FHeaderOut;
  2027. TLHTTPClientSocket(aSocket).FRequest := @FRequest;
  2028. TLHTTPClientSocket(aSocket).FResponse := @FResponse;
  2029. Result := inherited;
  2030. end;
  2031. procedure TLHTTPClient.InternalSendRequest;
  2032. begin
  2033. FOutputEof := false;
  2034. TLHTTPClientSocket(FIterator).SendRequest;
  2035. Inc(FPendingResponses);
  2036. if FState = hcsIdle then
  2037. FState := hcsWaiting;
  2038. end;
  2039. procedure TLHTTPClient.ResetRange;
  2040. begin
  2041. FRequest.RangeStart := High(FRequest.RangeStart);
  2042. FRequest.RangeEnd := High(FRequest.RangeEnd);
  2043. end;
  2044. procedure TLHTTPClient.SendRequest;
  2045. begin
  2046. if not Connected then
  2047. Connect(FHost, FPort)
  2048. else
  2049. InternalSendRequest;
  2050. end;
  2051. end.