Recent

Author Topic: [SOLVED] webserver does not receive files  (Read 876 times)

egsuh

  • Hero Member
  • *****
  • Posts: 1072
[SOLVED] webserver does not receive files
« on: December 04, 2022, 03:04:16 pm »
I was replying to questions on webserver related questions, but ironically I cannot make my own webserver to receive files. I think I had similar experience in the past, but cannot remember how I solved it.

Server-side code is as following. It will display the local file names.

Code: Pascal  [Select][+][-]
  1. procedure TwmWebTests.upfileRequest(Sender: TObject; ARequest: TRequest;
  2.   AResponse: TResponse; var Handled: Boolean);
  3. var
  4.    i: integer;
  5.    s: string;
  6. begin
  7.    s := Format('Files uploaded (count=%d):<br>', [ARequest.Files.Count]);
  8.    for i := 0 to ARequest.Files.Count-1 do begin
  9.        s += ARequest.Files[i].LocalFileName + '<br>';
  10.    end;
  11.    AResponse.Content := s;
  12.    Handled:= True;
  13. end;
  14.  

And html file that sends file to the server is :

Code: Text  [Select][+][-]
  1. <!Doctype html>
  2. <html>
  3. <head>
  4. </head>
  5. <body>
  6.  
  7. <form method="post" action="http://localhost/myapp/upfile" target="_blank">File Upload
  8.   <input type="file" name="files"><br>
  9.   <input type="submit">
  10. </form>
  11.  
  12. </body>
  13. </html>
  14.  

When I select a file and submit from the browser, it displays following. So, there are no problem in setting up webserver itself.

Quote
     Files Uploaded (count=0):

Server is Windows Server 2019 Standard.
« Last Edit: December 05, 2022, 06:28:05 am by egsuh »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8530
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: webserver does not receive files
« Reply #1 on: December 05, 2022, 12:47:40 am »
<form method="post" action="http://localhost/myapp/upfile" target="_blank">File Upload
File upload requires:
Code: Text  [Select][+][-]
  1. enctype="multipart/form-data"
  2.  
in the form attribute, cannot be with the default "application/x-www-form-urlencoded".

egsuh

  • Hero Member
  • *****
  • Posts: 1072
Re: webserver does not receive files
« Reply #2 on: December 05, 2022, 06:27:44 am »
Wow, now it works. Following is displayed on submission.

Quote
Files uploaded (count=1):
C:\Windows\TEMP\CGI00016.tmp

There are many web pages that explain how to write HTML for file uploads, but I couldn't find any example that specified enctype.
« Last Edit: December 05, 2022, 06:29:45 am by egsuh »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8530
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: webserver does not receive files
« Reply #3 on: December 06, 2022, 07:43:04 am »
There are many web pages that explain how to write HTML for file uploads, but I couldn't find any example that specified enctype.
No idea with that, when I first learned it back about 15 years ago, all tutorials specifically mention it. I guess today people don't really write HTML by hand and forget about this detail? I really don't know. But I do know many frameworks provide a function that only needs to be passed any element, typically div, then it magically turns into a file upload, hiding it from the programmer.

krolikbest

  • Full Member
  • ***
  • Posts: 194
Re: [SOLVED] webserver does not receive files
« Reply #4 on: December 07, 2022, 08:20:12 pm »
Hi,
to avoid create new thread I linked my question there. So simply code:
Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.    {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   sysutils, fphttpapp, HTTPDefs, fpwebfile, httproute;
  10.  
  11. procedure Test(aReq: TRequest; aRes: TResponse);
  12. var
  13.   n: Integer;
  14.   f: TUploadedFile;
  15.   i: Integer;
  16.   s : string;
  17.  
  18. begin
  19.    n := AReq.Files.Count;
  20.    if n = 0 then
  21.    begin
  22.       aRes.Code:=200;
  23.       aRes.Contents.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'fileUploader.html');
  24.    end
  25.       else
  26.    begin
  27.      f := AReq.Files[0];
  28.      f.LocalFileName:=ExtractFilePath(ParamStr(0)); //apparently this does not set a default folder
  29.      s:=f.LocalFileName;
  30.      ARes.Code:=200;
  31.      ARes.Content := s;
  32.    end;
  33. end;
  34.  
  35. begin
  36.   Application.Port:=8080;
  37.   HTTPRouter.RegisterRoute('/',@Test, true);
  38.   Application.threaded := true;
  39.   Application.Initialize;
  40.   Application.Run;
  41. end.                    
  42.  
It works but question is how can I set a specified folder on server side  for uploaded files? Using LocalFileName as I did seems to be incorrect..

Regards,

krolikbest

  • Full Member
  • ***
  • Posts: 194
Re: [SOLVED] webserver does not receive files
« Reply #5 on: December 07, 2022, 08:37:58 pm »
Ach, ok. Solved :)

Leledumbo

  • Hero Member
  • *****
  • Posts: 8530
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: [SOLVED] webserver does not receive files
« Reply #6 on: December 08, 2022, 04:41:41 am »
Left a trace for future people who have the same problem.

As in most other implementations, uploaded files are typically downloaded into a temporary directory. In fcl-web implementation, it's in whatever returned by GetTempDir, which typically reads TEMP environment variable so users can override it from the command line. There are however, multiple other ways to do the same from application level:
  • TRequest.DefaultRequestUploadDir, this is a class variable, can be set in global context not requiring any instance to be made first
  • Write your own HTTP server implementation with a TRequest descendant that overrides GetTempUploadFileName (to be honest, this is too much)
Just pick your option.

krolikbest

  • Full Member
  • ***
  • Posts: 194
Re: [SOLVED] webserver does not receive files
« Reply #7 on: December 08, 2022, 09:19:34 am »
     Hi,
 currently I'm writing without access to the code so a bit from memory but I did something like:
 
Code: Pascal  [Select][+][-]
  1.      f := AReq.Files[0];
  2.      s:=f.FileName;
  3.      ARes.Code:=200;
  4.      ARes.Contents.LoadFromStream(f.Stream); //this line loads contents of the uploaded file
  5.      ARes.Contents.SaveToFile(your_path_file); //this line save this contents to the new created file
  6.      ARes.Content := s;
  7.  
Of course such solution still writes in TempDir as well and to avoid it one need to follow your tips. Then there is no need to use my solution.

Regards,


egsuh

  • Hero Member
  • *****
  • Posts: 1072
Re: [SOLVED] webserver does not receive files
« Reply #8 on: December 08, 2022, 10:29:44 am »
Aren’t there anything like f.savetofile(your_file_path)?

krolikbest

  • Full Member
  • ***
  • Posts: 194
Re: [SOLVED] webserver does not receive files
« Reply #9 on: December 08, 2022, 12:30:40 pm »
Hi

 f is TUploadedFile class according to https://wiki.freepascal.org/fpWeb_Tutorial#Reading_File_Uploads. Didn't check if is it possible to simply use f.saveToFile.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8530
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: [SOLVED] webserver does not receive files
« Reply #10 on: December 08, 2022, 03:49:00 pm »
Aren’t there anything like f.savetofile(your_file_path)?
Unfortunately, no. This is the interface of TUploadedFile:
Code: Pascal  [Select][+][-]
  1.   TUploadedFile = Class(TCollectionItem)
  2.   Private
  3.     FContentType: String;
  4.     FDescription: String;
  5.     FDisposition: String;
  6.     FFieldName: String;
  7.     FFileName: String;
  8.     FLocalFileName: String;
  9.     FSize: Int64;
  10.     FStream : TStream;
  11.   Protected
  12.     // Note that this will free the file stream, to be able to close it - file is share deny write locked!
  13.     Procedure DeleteTempUploadedFile; virtual;
  14.     function GetStream: TStream; virtual;
  15.     Procedure FreeStream; virtual;
  16.   Public
  17.     Destructor Destroy; override;
  18.     Property FieldName : String Read FFieldName Write FFieldName;
  19.     Property FileName : String Read FFileName Write FFileName;
  20.     Property Stream : TStream Read GetStream;
  21.     Property Size : Int64 Read FSize Write FSize;
  22.     Property ContentType : String Read FContentType Write FContentType;
  23.     Property Disposition : String Read FDisposition Write FDisposition;
  24.     Property LocalFileName : String Read FLocalFileName Write FLocalFileName;
  25.     Property Description : String Read FDescription Write FDescription;
  26.   end;
  27.  
You can, however, make your own implementation that has such a method by extending this class and assigning it to httpdefs' UploadedFileClass variable. But for me, this interface is enough for most use cases. The Stream property is the key to do everything possible to uploaded files.

krolikbest

  • Full Member
  • ***
  • Posts: 194
Re: [SOLVED] webserver does not receive files
« Reply #11 on: December 08, 2022, 08:07:43 pm »
Hi,
Code: Pascal  [Select][+][-]
  1.       SetLength(f, AReq.Files.Count);
  2.       f[0] := AReq.Files[0];
  3.       ms:=TMemoryStream.Create;
  4.       f[0].Stream.Position:=0;
  5.       ms.CopyFrom(f[0].Stream, f[0].Stream.Size);
  6.       ms.SaveToFile(ExtractFilePath(ParamStr(0))+'\tst.txt');
  7.       ms.Free;            
  8.  

Regards,
« Last Edit: December 08, 2022, 08:17:58 pm by krolikbest »

 

TinyPortal © 2005-2018