Using HttpUpload function

delphi package - automated exception handling
Post Reply
user1
Posts: 12
Joined: Tue Apr 09, 2013 6:58 pm

Using HttpUpload function

Post by user1 »

I would like to upload / submit data using the custom script option. Using this "feature" I would like our customers to submit the snapshots of their configuration and certain files for troubleshooting. I've notices that there is a function HttpUpload(). So I wrote this:

Code: Select all

_di_IMEAttachments atts = NewAttachments();
_di_IMEFields fields = NewFields();
fields->Add("MailSubject", "Subject");
fields->Add("MailBody", "Body");
fields->Add("MailFrom", "myemail@ourserver.com");
HttpUpload("http://www.ourserver.com/bugreport.php", false, 80, UnicodeString("username-goes-here"), UnicodeString("password-goes-here"), atts, fields);
When I try to call the function from my program, it "sort of" works. The data is submitted to the script on our web server.
I've added a debug call to the php script right before the first if statement in the script.

Code: Select all

system("echo '".json_encode($_SERVER)."' >> /tmp/log");
Looking at the content of the log file I noticed that the request was missing the PHP_AUTH_DIGEST part.

If I to crash my program, it successfully submits a bug report. This time the request has PHP_AUTH_DIGEST part.
I could make a separate script that would ignore HTTP authentication and just process the request but I'm sure our web/network/admin people would not like that.

What is the proper way to call HttpUpload() function?

Thank you.
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: Using HttpUpload function

Post by madshi »

Hmmmm... I think there's a bug in the HttpUpload() code. Try this:

1) Copy madExcept.pas and mad.inc to your project folder.
2) In the HttpUpload() function change the following line to this:

Code: Select all

  with TWinHttp.Create(httpUrl, ssl, port, false, userName, password, '', '', proxyServer, proxyBypass, proxyUserName, proxyPassword, stngs, pa) do begin
Does this fix the problem?
user1
Posts: 12
Joined: Tue Apr 09, 2013 6:58 pm

Re: Using HttpUpload function

Post by user1 »

I did it and it worked.
I have another question about the SSL option. Do you know if the validity of the certificate on the server is verified if the SSL option is enabled?
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: Using HttpUpload function

Post by madshi »

To be honest, I've no idea. I'm letting Windows do all that work.
user1
Posts: 12
Joined: Tue Apr 09, 2013 6:58 pm

Re: Using HttpUpload function

Post by user1 »

I've figured it out I think.
Your current code is set to ignore any invalid certificates. In short, the SSL option is only used to encrypt the traffic but the authenticity of the server/SSL certificate is not verified. To verify authenticity of the server/certificate the following changes will need to be done:

1. Inside function TWinHttp.OpenRequest(const url, verb: AnsiString) comment out two lines:

Code: Select all

//flags := SECURITY_FLAG_IGNORE_CERT_CN_INVALID or SECURITY_FLAG_IGNORE_CERT_DATE_INVALID or SECURITY_FLAG_IGNORE_UNKNOWN_CA;
//WinHttpSetOption(FRequest, WINHTTP_OPTION_SECURITY_FLAGS, @flags, sizeOf(flags));
The above lines were instructing WinHTTP to ignore any invalid certificates.

2. Change function TWinHttp.SendRequest(sendData: AnsiString = ''; sizeOfAttachments: dword = 0) to :

Code: Select all

function TWinHttp.SendRequest(sendData: AnsiString = ''; sizeOfAttachments: dword = 0) : boolean;
const WINHTTP_AUTH_TARGET_PROXY = $00000001;
const ERROR_WINHTTP_SECURE_FAILURE = 12175;
var len : dword;
begin
  FRetrySend := false;
  if FProxyAuthScheme <> 0 then
    FRetrySend := WinHttpSetCredentials(FRequest, WINHTTP_AUTH_TARGET_PROXY, FProxyAuthScheme, PWideChar(FProxyUser), PWideChar(FProxyPassword), nil);
  result := WinHttpSendRequest(FRequest, nil, 0, nil, 0, dword(Length(sendData)) + sizeOfAttachments, 0);
  if (not result) then begin
    if (GetLastError <> ERROR_WINHTTP_SECURE_FAILURE) and (not FProxyDone) and (FProxyInfo.lpszProxy = nil) then begin
      FProxyDone := true;
      if AutoConfigProxy then
        result := WinHttpSendRequest(FRequest, nil, 0, nil, 0, dword(Length(sendData)) + sizeOfAttachments, 0);
    end;
  end;
  if result and (sendData <> '') then
    result := WinHttpWriteData(FRequest, pointer(sendData), Length(sendData), len);
  if not result then
    SetLastErrorNo;
end;
The difference from the original code is that if the first WinHttpSendRequest fails, we now check and make sure the the failure is not related to security before exploring the proxy option.
If the certificate on the server is invalid the HttpUpload function would return false and LastHttpErrorNo would be equal to 12175.
I tested the code on a self-signed certificate and a valid certificate located on a wrong domain (ex. certificate for mywebdomain.com was used on myfriendsdomain.com).
Using SSL with certificate verification can avoid sending data to the "wrong people" if your domain name gets hijacked.
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: Using HttpUpload function

Post by madshi »

Thank you for those code changes. I suppose using them means that the HTTP uploading gets stricter? I'm a bit afraid that this might break uploading for some users. What do you think?
user1
Posts: 12
Joined: Tue Apr 09, 2013 6:58 pm

Re: Using HttpUpload function

Post by user1 »

The change only affects connections with SSL enabled.
For those who use SSL to upload, not everybody might have a valid certificate. Some will have certificates that are self signed.
Certificate verification should be something user would have to opt in. Maybe change ssl type from bool to int and use value 2 to indicate "SSL with Valid Certificate", in the settings UI add another option in the SSL combobox.
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: Using HttpUpload function

Post by madshi »

The latest beta build should have your changes included now. However, they're disabled by default. You can enable them by setting the following variable, exported by madExcept.pas to true:

Code: Select all

var RequireAuthenticSsl : boolean = false;  // should SSL/TLS stuff require the certificate to be authentic?
Post Reply