lhttp.pp 59 KB

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