fcgi_dump_request.pp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. program fcgi_dump_request;
  2. {$mode objfpc}{$H+}
  3. uses
  4. Classes,
  5. SysUtils,
  6. httpDefs,
  7. fpweb,
  8. custweb,
  9. custfcgi,
  10. httpprotocol,
  11. fpjson,
  12. sha1;
  13. Type
  14. { TMyCGIHandler }
  15. TMyCGIHandler = Class(TFCgiHandler)
  16. protected
  17. function GetSHA1FileHash(const AFileName: string): string;
  18. Public
  19. procedure HandleRequest(ARequest : TRequest; AResponse : TResponse); override;
  20. function DumpHeaders(ARequest: TRequest): TJSONObject;
  21. function DumpContent(ARequest: TRequest): TJSONObject;
  22. function DumpFiles(ARequest: TRequest): TJSONArray;
  23. end;
  24. TMyCGIApp = Class(TCustomFCgiApplication)
  25. Protected
  26. function InitializeWebHandler: TWebHandler; override;
  27. end;
  28. var
  29. WebApp: TMyCGIApp;
  30. Procedure TMyCGIHandler.HandleRequest(ARequest : Trequest; AResponse : TResponse);
  31. var
  32. ResponseJson: TJSONObject;
  33. ShouldShutdown: Boolean;
  34. begin
  35. if not TryStrToBool(ARequest.QueryFields.Values['shutdown'], ShouldShutdown) then
  36. ShouldShutdown := False;
  37. ResponseJson := TJSONObject.Create();
  38. try
  39. ResponseJson.Add('headers', DumpHeaders(ARequest));
  40. ResponseJson.Add('content', DumpContent(ARequest));
  41. ResponseJson.Add('files', DumpFiles(ARequest));
  42. if ShouldShutdown then
  43. ResponseJson.Add('shutdown', True);
  44. AResponse.Content := ResponseJson.AsJSON;
  45. finally
  46. ResponseJson.Free;
  47. end;
  48. // Usefull for testing of memory-leaks
  49. if ShouldShutdown then
  50. WebApp.Terminate;
  51. end;
  52. function TMyCGIHandler.DumpHeaders(ARequest: TRequest): TJSONObject;
  53. var
  54. HeaderJson: TJSONObject;
  55. CustomHeaderJson: TJSONObject;
  56. Header: THeader;
  57. i: Integer;
  58. begin
  59. HeaderJson := TJSONObject.Create;
  60. try
  61. for Header := Low(Header) to High(Header) do
  62. if ARequest.HeaderIsSet(Header) then
  63. HeaderJson.Add(HTTPHeaderNames[Header], ARequest.GetHeader(Header));
  64. if ARequest.CustomHeaders.Count > 0 then
  65. begin
  66. CustomHeaderJson := TJSONObject.Create;
  67. HeaderJson.Add('custom', CustomHeaderJson);
  68. for i := 0 to ARequest.CustomHeaders.Count -1 do
  69. CustomHeaderJson.Add(ARequest.CustomHeaders.Names[i], ARequest.CustomHeaders.ValueFromIndex[i]);
  70. end;
  71. Result := HeaderJson;
  72. HeaderJson := nil;
  73. finally
  74. HeaderJson.Free;
  75. end;
  76. end;
  77. function TMyCGIHandler.DumpContent(ARequest: TRequest): TJSONObject;
  78. var
  79. ContentJson: TJSONObject;
  80. ContentFieldJson: TJSONArray;
  81. i: Integer;
  82. begin
  83. ContentJson := TJSONObject.Create;
  84. try
  85. if Length(ARequest.Content) > 250 then
  86. ContentJson.Add('rawTrimmed', TJSONObject.Create([
  87. 'length', Length(ARequest.Content),
  88. 'start', Copy(ARequest.Content, 1, 120),
  89. 'end', Copy(ARequest.Content, Length(ARequest.Content)-79, 120)
  90. ]))
  91. else
  92. ContentJson.Add('raw', ARequest.Content);
  93. if ARequest.ContentFields.Count > 0 then
  94. begin
  95. ContentFieldJson := TJSONArray.Create;
  96. ContentJson.Add('fields', ContentFieldJson);
  97. for i := 0 to ARequest.ContentFields.Count -1 do
  98. begin
  99. ContentFieldJson.Add(TJSONObject.Create([
  100. 'name', ARequest.ContentFields.Names[i],
  101. 'value' , ARequest.ContentFields.ValueFromIndex[i]]));
  102. end;
  103. end;
  104. Result := ContentJson;
  105. ContentJson := nil;
  106. finally
  107. ContentJson.Free;
  108. end;
  109. end;
  110. function TMyCGIHandler.DumpFiles(ARequest: TRequest): TJSONArray;
  111. var
  112. FileJsonArr: TJSONArray;
  113. FileJson: TJSONObject;
  114. i: Integer;
  115. UploadedFile: TUploadedFile;
  116. begin
  117. FileJsonArr := TJSONArray.Create;
  118. try
  119. for i := 0 to ARequest.Files.Count -1 do
  120. begin
  121. UploadedFile := ARequest.Files.Files[i];
  122. FileJson := TJSONObject.Create([
  123. 'filename', UploadedFile.FileName,
  124. 'localFillename', UploadedFile.LocalFileName,
  125. 'description', UploadedFile.Description,
  126. 'contentType', UploadedFile.ContentType,
  127. 'size', UploadedFile.Size,
  128. 'disposition', UploadedFile.Disposition,
  129. 'fieldname', UploadedFile.FieldName,
  130. 'sha1', GetSHA1FileHash(UploadedFile.LocalFileName)
  131. ]);
  132. FileJsonArr.Add(FileJson);
  133. DeleteFile(UploadedFile.LocalFileName);
  134. end;
  135. Result := FileJsonArr;
  136. FileJsonArr := nil;
  137. finally
  138. FileJsonArr.Free;
  139. end;
  140. end;
  141. function TMyCGIHandler.GetSHA1FileHash(const AFileName: string): string;
  142. begin
  143. if FileExists(AFileName) then
  144. Result := SHA1Print(SHA1File(AFileName));
  145. end;
  146. Function TMyCGIApp.InitializeWebHandler: TWebHandler;
  147. begin
  148. Result:=TMyCgiHandler.Create(self);
  149. end;
  150. begin
  151. WebApp := TMyCGIApp.Create(Nil);
  152. With WebApp do
  153. try
  154. { Uncomment the port setting here if you want to run the
  155. FastCGI application stand-alone (e.g. for NGINX) }
  156. Port := 7005;
  157. ProtocolOptions := [poReuseAddress];
  158. Initialize;
  159. Run;
  160. finally
  161. Free;
  162. end;
  163. end.