Delphi IdHTTP Post on Django-created Form - django

I'm posting the login-data from delphi on a django-created-form which runs on my localhost. Like this:
procedure TForm1.btnPostClick(Sender: TObject);
var
IdHTTP: TidHTTP;
auth: TStringList;
test,token:string;
begin
IdHTTP := TidHTTP.Create(nil);
IdHTTP.Request.Accept :='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
IdHTTP.Request.AcceptCharSet :='iso-8859-1, utf-8, utf-16, *;q=0.1';
IdHTTP.Request.AcceptEncoding :='deflate, gzip, identity, *;q=0';
IdHTTP.Request.Connection :='Keep-Alive';
IdHTTP.Request.ContentType :='application/x-www-form-urlencoded';
token := IdHTTP.Get('http://localhost:8000/accounts/signup/');
token := copy(token, AnsiPos('csrfmiddlewaretoken', token) + 28, 32);
IdHTTP.Request.CustomHeaders.Clear;
with IdHTTP.Request.CustomHeaders do
begin
AddValue('X-CSRFToken',token);
Values['COOKIE']:='';
//if IdHTTP2.CookieManager.CookieCollection.count > 0 then
// Add('COOKIE: '+token);
end;
try
auth := TStringList.Create;
auth.Add('csrfmiddlewaretoken='+ token);
auth.Add('first_name=' + edtVorname.Text);
auth.Add('last_name=' + edtName.Text);
auth.Add('function=' + edtFunction.Text);
auth.Add('company=' + edtCompany.Text);
auth.Add('country=' + edtCountry.Text);
auth.Add('email=' + edtEmail.Text);
auth.Add('password1=' + edtPassword.Text);
auth.Add('password2=' + edtPasswordAgain.Text);
//IdHTTP.Request.CustomHeaders.AddValue('Accept-Language', 'en-EN');
//IdHTTP.Request.CustomHeaders.AddValue('Referer',
IdHTTP.post('http://127.0.0.1:8000/accounts/signup/', auth);
except
end;
end;
Whenever it gets until the Line with the post
IdHTTP.post('http://127.0.0.1:8000/accounts/signup/', auth);
Im getting the 403 error "Forbidden". My guess is im sending the CSRF-Token wrong
because from the python debugger I see being caught in
if csrf_token is None:
# No CSRF cookie. For POST requests, we insist on a CSRF cookie,
# and in this way we can avoid all CSRF attacks, including login
# CSRF.
return self._reject(request, REASON_NO_CSRF_COOKIE)
But HOW is it supposed to be? How do I need to send this csrf-token?
P.S Well I think the problem was that per default HandleRedirects is set to True and it gave me the 403. The cookievalue in the latest Django versions is usually called csrftoken and not X-CSRFToken how I did here.

You shouldn't set cookie by yourself. When Django response with a form and django.middleware.csrf.CsrfViewMiddleware is in your list of middleware classes (more on https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/), it should already set csrftoken cookie. So you only have to read value of this cookie and set it to csrfmiddlewaretoken form field.
Also don't forget to set UserAgent in your request. Without UserAgent Indy (Delphi 2010) and Django 1.8 won't cooperate with each other.
I don't know how to add csrfmiddlewaretoken field on redirects so I did it without redirects!
Here is my code:
uses
IdURI, IdCookie;
...
procedure TForm1.btnLoginClick(Sender: TObject);
var
idHTTP: TIdHTTP;
token: AnsiString;
stream: TStringStream;
params: TStringList;
cookie: TidCookieRFC2109;
begin
idHTTP := TIdHTTP.Create(nil);
stream := TStringStream.Create;
params := TStringList.Create;
try
idHTTP.AllowCookies := True;
idHTTP.HandleRedirects := False;
//even if HandleRedirects := False, you must have OnRedirect event (don't know why)
idHTTP.OnRedirect := IdHttpOnRedirect;
IdHTTP.Request.Accept := 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
IdHTTP.Request.AcceptCharSet := 'iso-8859-1, utf-8, utf-16, *;q=0.1';
IdHTTP.Request.AcceptEncoding := 'gzip, deflate, sdch';
IdHTTP.Request.Connection := 'Keep-Alive';
IdHTTP.Request.ContentType := 'application/x-www-form-urlencoded';
idHTTP.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36';
idHTTP.Request.CharSet := 'utf-8';
idHTTP.Get('http://www.ttaksa.si/login/');
cookie := idHTTP.CookieManager.CookieCollection.Cookie['csrftoken', '.www.ttaksa.si'];
token := cookie.Value;
params.Values['csrfmiddlewaretoken'] := token;
params.Values['username'] := txtUporabniskoIme.Text;
params.Values['password'] := txtGeslo.Text;
idHTTP.Post('http://www.ttaksa.si/login/', params, stream);
idHTTP.Get('http://www.ttaksa.si/objekti/export/?zacetni_datum=23.7.2015-12:00:00&format=xml&indent=2', stream);
stream.SaveToFile(txtFilename.Text);
wbUvoz.Navigate('File://' + txtFilename.Text);
finally
idHTTP.Free;
stream.Free;
params.Free;
end;
end;
procedure TForm1.IdHTTPOnRedirect(Sender: TObject; var dest: string;
var NumRedirect: Integer; var Handled: boolean; var VMethod: TIdHTTPMethod);
begin
Handled := True;
end;

Related

Sending an email with RAW content using AWS Pinpoint and Go returns 403

I'm trying to send an email via AWS pinpoint containing attachments. To send attachments with an email, you must use the 'RAW' email content. The only documentation I can find about this is here: https://docs.aws.amazon.com/pinpoint-email/latest/APIReference/API_RawMessage.html, but it is missing quite a few things (like, what are the required headers?)
When I send an email using the 'simple' content, it works fine:
emailInput := &pinpointemail.SendEmailInput{
Destination: &pinpointemail.Destination{
ToAddresses: []*string{&address},
},
FromEmailAddress: &sender,
Content: &pinpointemail.EmailContent{
Simple: &pinpointemail.Message{
Body: &pinpointemail.Body{
Html: &pinpointemail.Content{
Charset: &charset,
Data: &emailHTML,
},
Text: &pinpointemail.Content{
Charset: &charset,
Data: &emailText,
},
},
Subject: &pinpointemail.Content{
Charset: &charset,
Data: &emailSubject,
},
},
}
Since I want to add attachments, I have to use the 'RAW' content type. I have written a function which generates the email content, based on: https://gist.github.com/douglasmakey/90753ecf37ac10c25873825097f46300:
func generateRawEmailContent(subject, to, from, HTMLBody string, attachments *[]EmailAttachment) []byte {
buf := bytes.NewBuffer(nil)
buf.WriteString(fmt.Sprintf("Subject: %s\n", subject))
buf.WriteString(fmt.Sprintf("To: %s\n", to))
buf.WriteString(fmt.Sprintf("From: %s\n\n", from))
buf.WriteString("MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n")
buf.WriteString(HTMLBody)
writer := multipart.NewWriter(buf)
boundary := writer.Boundary()
buf.WriteString(fmt.Sprintf("Content-Type: multipart/mixed; boundary=%s\n", boundary))
buf.WriteString(fmt.Sprintf("--%s\n", boundary))
for _, attachment := range *attachments {
buf.WriteString(fmt.Sprintf("\n\n--%s\n", boundary))
buf.WriteString(fmt.Sprintf("Content-Type: %s\n", http.DetectContentType(attachment.Data)))
buf.WriteString("Content-Transfer-Encoding: base64\n")
buf.WriteString(fmt.Sprintf("Content-Disposition: attachment; filename=%s\n", attachment.FileName))
b := make([]byte, base64.StdEncoding.EncodedLen(len(attachment.Data)))
base64.StdEncoding.Encode(b, attachment.Data)
buf.Write(b)
buf.WriteString(fmt.Sprintf("\n--%s", boundary))
}
buf.WriteString("--")
log.Println(string(buf.Bytes()))
return buf.Bytes()
}
This generates the following (emails changed):
Subject: Welcome \nTo: xxxxx#gmail.com\nFrom: xxxxx#gmail.com\n\nMIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n\u003ch1\u003eHello ,\u003c/h1\u003e\u003cp\u003eYou now have an account.\u003c/p\u003e\nContent-Type: multipart/mixed; boundary=8f6b2cc498b79f5a99550b930ba1ecab1fc1ee2d3425a0a69ab67b83b647\n--8f6b2cc498b79f5a99550b930ba1ecab1fc1ee2d3425a0a69ab67b83b647\n\n\n--8f6b2cc498b79f5a99550b930ba1ecab1fc1ee2d3425a0a69ab67b83b647\nContent-Type: text/plain; charset=utf-8\nContent-Transfer-Encoding: base64\nContent-Disposition: attachment; filename=test.json\newogICJ0ZXN0IjogdHJ1ZQp9\n--8f6b2cc498b79f5a99550b930ba1ecab1fc1ee2d3425a0a69ab67b83b647--
I then construct the email as follows:
&pinpointemail.SendEmailInput{
Destination: &pinpointemail.Destination{
ToAddresses: []*string{&address},
},
FromEmailAddress: &sender,
Content: &pinpointemail.EmailContent{
Raw: &pinpointemail.RawMessage{
Data: generateRawEmailContent(emailSubject, address, sender, emailHTML, emailAttachments),
},
}
When sending this email via the github.com/aws/aws-sdk-go/service/pinpoint package, I get a 403 returned, and I have no idea why. A 403 means that the resource I'm trying to access is forbidden, but I don't see how that is relevant here? Also, there is no documentation about a 403 even being a possible response. Any help would be greatly appreciated!
I have also tried using libraries, like for instance the gomail-v2 library as follows:
m := gomail.NewMessage()
m.SetHeader("From", from)
m.SetHeader("To", to)
m.SetHeader("Subject", subject)
m.SetBody("text/plain", textBody)
m.AddAlternative("text/html", HTMLBody)
m.Attach("foo.txt", gomail.SetCopyFunc(func(w io.Writer) error {
_, err := w.Write((*attachments)[0].Data)
return err
}))
buf := bytes.NewBuffer(make([]byte, 0, 2048))
_, werr := m.WriteTo(buf)
if werr != nil {
return nil, common.NewStackError(werr)
}
But that still gives me a 403 error.
I'm not a Go person, so this is just a brutal attempt to shuffle around code lines to hopefully produce a valid MIME structure.
func generateRawEmailContent(subject, to, from, HTMLBody string, attachments *[]EmailAttachment) []byte {
buf := bytes.NewBuffer(nil)
// Creating headers by gluing together strings is precarious.
// I'm sure there must be a better way.
buf.WriteString(fmt.Sprintf("Subject: %s\n", subject))
buf.WriteString(fmt.Sprintf("To: %s\n", to))
// Remove spurious newline
buf.WriteString(fmt.Sprintf("From: %s\n", from))
writer := multipart.NewWriter(buf)
boundary := writer.Boundary()
buf.WriteString(fmt.Sprintf("MIME-Version: 1.0\n", boundary))
buf.WriteString(fmt.Sprintf("Content-Type: multipart/mixed; boundary=%s\n", boundary))
// End of headers
buf.WriteString("\n")
buf.WriteString(fmt.Sprintf("--%s\n", boundary))
buf.WriteString("Content-Type: text/html; charset=\"UTF-8\";\n\n")
buf.WriteString(HTMLBody)
for _, attachment := range *attachments {
buf.WriteString(fmt.Sprintf("\n\n--%s\n", boundary))
buf.WriteString(fmt.Sprintf("Content-Type: %s\n", http.DetectContentType(attachment.Data)))
buf.WriteString("Content-Transfer-Encoding: base64\n")
buf.WriteString(fmt.Sprintf("Content-Disposition: attachment; filename=%s\n", attachment.FileName))
b := make([]byte, base64.StdEncoding.EncodedLen(len(attachment.Data)))
base64.StdEncoding.Encode(b, attachment.Data)
buf.Write(b)
// Don't add a second boundary here
buf.WriteString("\n")
}
// Final terminating boundary, notice -- after
buf.WriteString(fmt.Sprintf("\n--%s--\n", boundary))
log.Println(string(buf.Bytes()))
return buf.Bytes()
}
The resulting output should look something like
Subject: subject
To: recipient <victim#example.org>
From: me <sender#example.net>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=foobar
--foobar
Content-Type: text/html; charset="UTF-8"
<h1>Tremble, victim</h1>
<p>We don't send <tt>text/plain</tt> because we
hate our users.</p>
--foobar
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=skull_crossbones.jpg
YmluYXJ5ZGF0YQ==
--foobar--
Okay, found the issue. Turns out that this 403 error has nothing to do with my code, but rather with IAM permissions in AWS. Apparently an IAM permission has to be turned on to enable RAW email content.

Trying to log into Amazon.com to pull data, but getting an Enable Cookies response (using Go)

I'm trying to use Go to log into my account on Amazon to automatically pull some information, but I'm having trouble logging in because it complains about cookies. Here's a sanitized version of the code I was using:
package main
import (
"bytes"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"strconv"
)
func CheckThis(AmazonUsername string, AmazonPassword string) error {
var LogonURL string
// Set the url
LogonURL = "https://www.amazon.com/ap/signin"
// Craft some form data
form := url.Values{}
form.Add("appAction", "SIGNIN")
form.Add("email", AmazonUsername)
form.Add("password", AmazonPassword)
form.Add("create", "0")
form.Add("appActionToken", “$VALUE”)
form.Add("openid.pape.max_auth_age", "$VALUE==")
form.Add("openid.identity", "$VALUE=")
form.Add("openid.assoc_handle", "$VALUE")
form.Add("openid.mode", "$VALUE")
form.Add("openid.ns.pape", "$VALUE==")
form.Add("openid.claimed_id", "$VALUE=")
form.Add("pageId", "$VALUE")
form.Add("openid.ns", "$VALUE=")
// Amazon sells cookies
cookieJar, _ := cookiejar.New(nil)
// Create a new client with the cookiejar in the struct...
client := &http.Client{
Jar: cookieJar,
}
// Craft the request to send to the website with the form containing login info
req, _ := http.NewRequest("POST", LogonURL, bytes.NewBufferString(form.Encode()))
// Some more headers
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Content-Length", strconv.Itoa(len(form.Encode())))
req.Header.Add("Accept-Language", "en-US,en;q=0.8")
req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
req.Header.Add("Connection", "keep-alive")
req.Header.Add("Host", "www.amazon.com")
req.Header.Add("Referer", "https://www.amazon.com/ap/signin")
req.Header.Add("Upgrade-Insecure-Requests", "1")
req.Header.Add("Origin", "https://www.amazon.com")
req.Header.Add("Cache-Control", "max-age=0")
// And we're off to the races...
resp, _ := client.Do(req)
// What was in the response?
charResponse, _ := ioutil.ReadAll(resp.Body)
resp.Body.Close()
// Write response body to a text file with title of…
_ = WriteOutputToFile(string(charResponse), “response.html")
// All done!
return nil
}
The $VALUE entries are because I'm not sure if the strings are significant to my account so I removed them; these are values I pulled from the developer tools of a Chrome login session. I also removed err checks for brevity.
The reply page (opening response.html on my drive within Chrome) looks like this:
What am I missing in order to keep the cookie with the client req/resp for the sign-in and later pages?
Or am I missing something where the response page I save is trying to pull elements from Amazon when I render the HTML, and the cookie issue is because the browser would be missing cookie information when I'm trying to view the results from the Go application?
I'm pretty sure Amazon uses different data every time when you try to login so better to parse login form. Here is example
package main
import (
"bytes"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"github.com/PuerkitoBio/goquery"
"log"
)
func checkError(err error) {
if err != nil {
log.Fatal(err)
}
}
func CheckThis(AmazonUsername string, AmazonPassword string) error {
cookieJar, _ := cookiejar.New(nil)
client := &http.Client{
Jar: cookieJar,
}
res, err := client.Get("https://www.amazon.com/gp/sign-in.html/ref=ord_cart_unrec_signin")
checkError(err)
doc, err := goquery.NewDocumentFromResponse(res)
form := url.Values{}
doc.Find("form[name='signIn'] input").Each(func(i int, s *goquery.Selection) {
name, exist := s.Attr("name")
if exist {
value, exist := s.Attr("value")
if exist {
form.Add(name, value)
}
}
})
form.Set("email", AmazonUsername)
form.Set("password", AmazonPassword)
req, _ := http.NewRequest("POST", "https://www.amazon.com/ap/signin", bytes.NewBufferString(form.Encode()))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, err = client.Do(req)
checkError(err)
defer res.Body.Close()
charResponse, _ := ioutil.ReadAll(res.Body)
ioutil.WriteFile("response.html", charResponse, 0777)
return nil
}
func main() {
CheckThis("", "")
}
Amazon's index is setting this (and much more) cookies on my browser:
I suppose you need to set them into cookiejar in order to simulate a browser (amazon excepts that from your request, so is telling you have no cookies enabled because there isn't a required security value).
I agree with #JimB, you should be using Amazon SDK. Is there any reason why you are not doing this way?
Best regards.

DSSesssion in delphi Xe5

How to use DSSession to implements DataSnap authenticated sessions(HTTP/HTTPs)?????
My problems are:
I try to login into Login.html, then login complete Server Redirect into home.html
But in page Home.html not identified yet, So cant use Function.ServerMethod();
I wana to SetCredential(user:pass) in Home page used DSSession or anythings same.
In Home page , if not login, Redirect into Login again.
Before in Login.html confirm user and pass :
procedure TWebModule1.DSAuthenticationManager1UserAuthenticate(
Sender: TObject; const Protocol, Context, User, Password: string;
var valid: Boolean; UserRoles: TStrings);
var
session: TDSSession;
begin
//valid := True;
FormMain.Debug(['Before IsLogin : ',IsLogin],'?');
if not IsLogin then
IsLogin := (User = Password) and (user <> '');
valid := IsLogin;
FormMain.Debug(['IsLogin : ',IsLogin],'?');
FormMain.Debug(['UserAuthenticate :',User,Password],'?');
if valid = true then
FormMain.Debug(['UserAuthenticate : valid = true'],'?')
else
FormMain.Debug(['UserAuthenticate : valid = false'],'?');
if valid then
begin
Session := TDSSessionManager.GetThreadSession;
Session.PutData ('username', user);
UserRoles.Add ('standard');
if User = 'admin' then
UserRoles.Add ('admin');
end;
end;
Then redirect into Home.html. But in this page cant use Serverfunction(). ( errror 404, not Unauthorize)

Post JSON data to RESTful datasnap server from delphi client

I need to send a simple JSON object to a Restful datasnap server (Delphi) from a Delphi client. I am using Delphi XE. Can anybody help me out with the code? I am trying for hours but not getting it.. Please ask if details are not sufficient
Edit:
Here is server side method declaration:
procedure updatemethodnme(str:string):string;
and here is client side code:
function PostData(request: string): boolean;
var
param: TStringList;
url, Text,str: string;
code: Integer;
http: TIDHttp;
begin
Result:= false;
http:= TIDHttp.Create(nil);
http.HandleRedirects:= true;
http.ReadTimeout:= 50000;
http.request.Connection:= 'keep-alive';
str:= '{"lamp":"'+lamp+'","floor":"'+floor+'","op":"'+request+'"}';
param:= TStringList.Create;
param.Clear;
param.Add(str);
url:= 'h***p://xx2.168.xx.xx:xxxx/Datasnap/rest/TserverMethods1/methdname/';
try
Text:= http.Post(url, param);
Result:= true;
except on E: Exception do
begin
Result := false;
end;
end;
end;
Here's some simple XE2 test code sending JSON data through HTTP Post using SuperObject (using Indy's TIdHTTP):
procedure TFrmTTWebserviceTester.Button1Click(Sender: TObject);
var
lJSO : ISuperObject;
lRequest: TStringStream;
lResponse: String;
begin
// Next 2 lines for Fiddler HTTP intercept:
IdHTTP.ProxyParams.ProxyServer := '127.0.0.1';
IdHTTP.ProxyParams.ProxyPort := 8888;
lJSO := SO('{"name": "Henri Gourvest", "vip": true, "telephones": ["000000000", "111111111111"], "age": 33, "size": 1.83, "adresses": [ { "adress": "blabla", "city": "Metz", "pc": 57000 }, { "adress": "blabla", "city": "Nantes", "pc": 44000 } ]}');
lRequest := TStringStream.Create(lJSO.AsString, TEncoding.UTF8);
try
IdHTTP.Request.ContentType := 'application/json';
IdHTTP.Request.Charset := 'utf-8';
try
lResponse := IdHTTP.Post('http://127.0.0.1:8085/ttposttest', lRequest);
ShowMessage(lResponse);
except
on E: Exception do
ShowMessage('Error on request:'#13#10 + E.Message);
end;
finally
lRequest.Free;
end;
lJSO := nil;
end;
This is the data that goes out:
POST http://127.0.0.1:8085/ttposttest HTTP/1.0
Content-Type: application/json; charset=utf-8
Content-Length: 204
Connection: keep-alive
Host: 127.0.0.1:8085
Accept: text/html, */*
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)
{"vip":true,"age":33,"telephones":["000000000","111111111111"],"adresses":[{"adress":"blabla","pc":57000,"city":"Metz"},{"adress":"blabla","pc":44000,"city":"Nantes"}],"size":1.83,"name":"Henri Gourvest"}
Receiver is a TWebAction on a TWebModule, with handler:
procedure TWebModuleWebServices.WebModuleWebServicesTTPostTestAction(
Sender: TObject; Request: TWebRequest; Response: TWebResponse;
var Handled: Boolean);
var
S : String;
lJSO: ISuperObject;
begin
S := Request.Content;
if S <> '' then
lJSO := SO('{"result": "OK", "encodingtestcharacters": "Typed € with Alt-0128 Will be escaped to \u20ac"}')
else
lJSO := SO('{"result": "Error", "message": "No data received"}');
Response.ContentType := 'application/json'; // Designating the encoding is somewhat redundant for JSON (http://stackoverflow.com/questions/9254891/what-does-content-type-application-json-charset-utf-8-really-mean)
Response.Charset := 'utf-8';
Response.Content := lJSO.AsJSON;
Handled := true;
end; { WebModuleWebServicesTTPostTestAction }
It uses TIdHTTPWebBrokerBridge:
FWebBrokerBridge := TIdHTTPWebBrokerBridge.Create(Self);
// Register web module class.
FWebBrokerBridge.RegisterWebModuleClass(TWebModuleWebServices);
// Settings:
FWebBrokerBridge.DefaultPort := 8085;
This is the actual response:
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json; charset=utf-8
Content-Length: 92
{"encodingtestcharacters":"Typed\u20acwithAlt0128FollowedBy8364escaped\u8364","result":"OK"}
You can use Indy's TIdHTTP component to Post() JSON-encoded data to a REST server. You would simply have to encode and decode the JSON data in your own code.
From Delphi6 posting to a datasnap server built in XE5 the above works for me, but I had found out the server method needed the parameter to be defined as a TJSONObject instead of TStream. Something odd in addition to this, the Datansap server changes the lookup method when you do a post instead of a get. For example I had a method named ImportData. But when you debug the server it was looking for an UpdateImportData method. So when I added the new method and changed the parameter type to Data.DBXJSON.TJSONObject it worked.

Call UPS Parcel Tracking Web Service with Delphi?

Delphi 2009 imported the UPS WSDL without any errors, and I managed to invoke the web service with my account information and an example parcel ID. The response from the server is:
<detail>
<err:Errors xmlns:err="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1">
<err:ErrorDetail>
<err:Severity>Hard</err:Severity>
<err:PrimaryErrorCode>
<err:Code>9150002</err:Code>
<err:Description>Invalid or missing inquiry number - TrackingNumber, ShipmentIdentificationNumber, or ReferenceNumber</err:Description>
</err:PrimaryErrorCode>
</err:ErrorDetail>
</err:Errors>
</detail>
Has somebody already sucessfully used the UPS Parcel Tracking web service with a Delphi client, and knows what is wrong?
Here is the client code:
var
Service: TrackPortType;
MyRequest: TrackRequest;
Security: UPSSecurity;
MyResponse: TrackResponse;
ReqOpt: Array_Of_string;
begin
Service := (HTTPRIO1 as TrackPortType);
Security := UPSSecurity.Create;
Security.UsernameToken := UsernameToken.Create;
Security.UsernameToken.Username := 'username';
Security.UsernameToken.Password := 'password';
Security.ServiceAccessToken := ServiceAccessToken.Create;
Security.ServiceAccessToken.AccessLicenseNumber := 'licensenumber';
MyRequest := TrackRequest.Create;
SetLength(ReqOpt, 1);
ReqOpt[0] := '0';
MyRequest.Request := Request.Create;
MyRequest.Request.RequestOption := ReqOpt;
MyRequest.TrackingOption := '02';
MyRequest.InquiryNumber := '1Z...';
try
(Service as ISoapHeaders).Send(Security);
MyResponse := Service.ProcessTrack(MyRequest, nil);
except
on E:ERemotableException do
begin
Memo1.Lines.Text := FormatXmlData(E.FaultDetail);
end;
end;
Solved it with the Java API for XML Web Services (JAX-WS).
To integrate with Delphi, I proxy it as an Intranet Servlet. The Delphi GUI application then can use a simple HTTP request to query the tracking status.
Update: in a second attempt to get it working in Delphi, I hardcoded the SOAP XML request body, and used Indy and XMLDocument instead of the Delphi SOAP library.