(* Feel free to use this example code in any way you see fit (Public Domain) *) // Original example: https://gnunet.org/svn/libmicrohttpd/doc/examples/largepost.c program largepost; {$mode objfpc}{$H+} uses libmicrohttpd, SysUtils, cutils; type TConnectionInfoStruct = record ConnectionType: cint; PostProcessor: PMHD_PostProcessor; Fp: FILEptr; AnswerString: Pcchar; AnswerCode: cint; end; PConnectionInfoStruct = ^TConnectionInfoStruct; const PORT = 8888; POSTBUFFERSIZE = 512; MAXCLIENTS = 2; GET = 0; POST = 1; var NrOfUploadingClients: Cardinal; AskPage: Pcchar = ''+#10+ 'Upload a file, please!
'+#10+ 'There are %d clients uploading at the moment.
'+#10+ '
'+#10+ ''+#10+ '
'+#10+ ''; BusyPage: Pcchar = 'This server is busy, please try again later.'; CompletePage: Pcchar = 'The upload has been completed.'; ErrorPage: Pcchar = 'This doesn''t seem to be right.'; ServerErrorPage: Pcchar = 'An internal server error has occurred.'; FileExistsPage: Pcchar = 'This file already exists.'; function SendPage(AConnection: PMHD_Connection; APage: Pcchar; AStatusCode: cint): cint; var VRet: cint; VResponse: PMHD_Response; begin VResponse := MHD_create_response_from_buffer(Length(APage), Pointer(APage), MHD_RESPMEM_MUST_COPY); if not Assigned(VResponse) then Exit(MHD_NO); MHD_add_response_header(VResponse, MHD_HTTP_HEADER_CONTENT_TYPE, 'text/html'); VRet := MHD_queue_response(AConnection, AStatusCode, VResponse); MHD_destroy_response(VResponse); Result := VRet; end; function IteratePost(AConInfoCls: Pointer; AKind: MHD_ValueKind; AKey: Pcchar; AFileName: Pcchar; AContentType: Pcchar; ATransferEncoding: Pcchar; AData: Pcchar; AOff: cuint64; ASize: size_t): cint; cdecl; var VConInfo: PConnectionInfoStruct; begin VConInfo := AConInfoCls; VConInfo^.AnswerString := ServerErrorPage; VConInfo^.AnswerCode := MHD_HTTP_INTERNAL_SERVER_ERROR; if StrComp(AKey, 'file') <> 0 then Exit(MHD_NO); if not Assigned(VConInfo^.Fp) then begin if FileExists(AFileName) then begin VConInfo^.AnswerString := FileExistsPage; VConInfo^.AnswerCode := MHD_HTTP_FORBIDDEN; Exit(MHD_NO); end; VConInfo^.Fp := fopen(AFileName, fappendwrite); if not Assigned(VConInfo^.Fp) then Exit(MHD_NO); end; if ASize > 0 then if fwrite(AData, ASize, SizeOf(AnsiChar), VConInfo^.Fp) = 0 then Exit(MHD_NO); VConInfo^.AnswerString := CompletePage; VConInfo^.AnswerCode := MHD_HTTP_OK; Result := MHD_YES; end; procedure RequestCompleted(ACls: Pointer; AConnection: PMHD_Connection; AConCls: PPointer; AToe: MHD_RequestTerminationCode); cdecl; var VConInfo: PConnectionInfoStruct; begin VConInfo := AConCls^; if not Assigned(VConInfo) then Exit; if VConInfo^.ConnectionType = POST then begin if Assigned(VConInfo^.PostProcessor) then begin MHD_destroy_post_processor(VConInfo^.PostProcessor); Dec(NrOfUploadingClients); end; if Assigned(VConInfo^.Fp) then fclose(VConInfo^.Fp); end; FreeMem(VConInfo); AConCls^ := nil; end; function AnswerToConnection(ACls: Pointer; AConnection: PMHD_Connection; AUrl: Pcchar; AMethod: Pcchar; AVersion: Pcchar; AUploadData: Pcchar; AUploadDataSize: Psize_t; AConCls: PPointer): cint; cdecl; var VBuffer: array[0..1024] of AnsiChar; VConInfo: PConnectionInfoStruct; begin if not Assigned(AConCls^) then begin if NrOfUploadingClients >= MAXCLIENTS then Exit(SendPage(AConnection, BusyPage, MHD_HTTP_SERVICE_UNAVAILABLE)); VConInfo := AllocMem(SizeOf(TConnectionInfoStruct)); if not Assigned(VConInfo) then Exit(MHD_NO); VConInfo^.Fp := nil; if StrComp(AMethod, 'POST') = 0 then begin VConInfo^.PostProcessor := MHD_create_post_processor(AConnection, POSTBUFFERSIZE, @IteratePost, VConInfo); if not Assigned(VConInfo^.PostProcessor) then begin FreeMem(VConInfo); Exit(MHD_NO); end; Inc(NrOfUploadingClients); VConInfo^.ConnectionType := POST; VConInfo^.AnswerCode := MHD_HTTP_OK; VConInfo^.AnswerString := CompletePage; end else VConInfo^.ConnectionType := GET; AConCls^ := VConInfo; Exit(MHD_YES); end; if StrComp(AMethod, 'GET') = 0 then begin StrLFmt(VBuffer, SizeOf(VBuffer), AskPage, [NrOfUploadingClients]); Exit(SendPage(AConnection, VBuffer, MHD_HTTP_OK)); end; if StrComp(AMethod, 'POST') = 0 then begin VConInfo := AConCls^; if AUploadDataSize^ <> 0 then begin MHD_post_process(VConInfo^.PostProcessor, AUploadData, AUploadDataSize^); AUploadDataSize^ := 0; Exit(MHD_YES); end else begin if Assigned(VConInfo^.Fp) then begin fclose(VConInfo^.Fp); VConInfo^.Fp := nil; end; (* Now it is safe to open and inspect the file before calling send_page with a response *) Exit(SendPage(AConnection, VConInfo^.AnswerString, VConInfo^.AnswerCode)); end; end; Result := SendPage(AConnection, ErrorPage, MHD_HTTP_BAD_REQUEST); end; var VDaemon: PMHD_Daemon; begin VDaemon := MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, nil, nil, @AnswerToConnection, nil, MHD_OPTION_NOTIFY_COMPLETED, @RequestCompleted, nil, MHD_OPTION_END); if not Assigned(VDaemon) then Halt(1); ReadLn; MHD_stop_daemon(VDaemon); end.