lhttp.pp 59 KB

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