I followed the demo and things are working just fine. My client has a single function to send commands to the server and handle the response.
That was fine for the first few command and I handle it by
var result : String;
TCPclient.SendCmd(theMessage);
TCPclient.GetResponse(Result);
if Result <> 'OK' then ....
Where the server is sending
ASender.Reply.SetReply(200, 'OK'); ... or ...
ASender.Reply.SetReply(400, 'NAK');
Now, I want to add a new command and the result will be either NAK or ACK PLUS a value 0, 1 or 2
I am hazy on response codes which seem to have two parameters, one numerical and one textual ....
I could just kludge and send 'Ok0', 'OK1', or 'OK2', but that is very ugly (and probably A Bad Thing)
I think I though to use 200 for success and send 0, 1 or 2 in the textual parameter (or use 'OK' and send 0, 1 or 2 as numeric code, or use 200, 201, 202 as numeral code)?
Can someone please help me understand what I ought to be coding and why? (Or just point me at a URL) Thanks
SendCmd() reads the response from the server for you, so DO NOT call GetResponse() after SendCmd() unless the server actually sends two separate responses.
Responses typically take the form:
<Response Code> <Optional Text>
Where the response code is either a number or a textual keyword.
If the server sends numeric response codes, handle it like this:
Server:
// sends:
//
// 200 1
//
ASender.Reply.SetReply(200, '1');
Client:
if TCPclient.SendCmd(theMessage) = 200 then
Value := StrToInt(TCPclient.LastCmdResult.Text.Text);
Or:
// raises an exception if a non-200 response is received
TCPclient.SendCmd(theMessage, 200);
Value := StrToInt(TCPclient.LastCmdResult.Text.Text);
If the server sends textual response codes, handle it like this:
Server:
// sends:
//
// OK 1
//
ASender.Reply.SetReply('OK', '1');
Client:
if TCPclient.SendCmd(theMessage, '') = 'OK' then
Value := StrToInt(TCPclient.LastCmdResult.Text.Text);
Or:
// raises an exception if a non-OK response is received
TCPclient.SendCmd(theMessage, ['OK']);
Value := StrToInt(TCPclient.LastCmdResult.Text.Text);
The optional text of the response, if present, can be accessed in the TCPclient.LastCmdResult.Text property, which is a TStrings as it is possible to send multi-line responses in the form:
<Response Code>-<Optional Text>
<Response Code>-<Optional Text>
...
<Response Code> <Optional Text>
Server:
// sends:
//
// 200-The value is
// 200 1
//
ASender.Reply.SetReply(200, 'The value is');
ASender.Reply.Text.Add('1');
Client:
TCPclient.SendCmd(theMessage, 200);
Value := StrToInt(TCPclient.LastCmdResult.Text[1]);
You can also send secondary multi-line text after the responses in this form:
<Response Code> <Optional Text>
<Secondary Text>
.
Server:
// sends:
//
// 200 Data follows
// Hello world
// How are you?
// .
//
ASender.Reply.SetReply(200, 'Data follows');
ASender.Reply.Response.Add('Hello world');
ASender.Reply.Response.Add('How are you?');
Client:
TCPclient.SendCmd(theMessage, 200);
TCPclient.IOHandler.Capture(SomeTStringsObj);
Related
This seems to cause strange behaviour when PUT has a body larger than a certain length (in my case it is 902 bytes), i.e. ejabberd trims the body (in my case it receives malformed JSON).
Github reference: https://github.com/processone/ejabberd/blob/master/src/ejabberd_http.erl#L403
If I change the case statement to:
case Method of
_AnyMethod ->
case recv_data(State) of
{ok, Data} ->
LQuery = case catch parse_urlencoded(Data) of
{'EXIT', _Reason} -> [];
LQ -> LQ
end,
{State, {LPath, LQuery, Data}};
error ->
{State, false}
end
end
then the body is parsed correctly.
Is this a configuration issue? How can I force Ejabberd to correctly parse the JSON body?
Looks like you've found a bug.
As you've noticed, for POST requests the function recv_data is called, which checks the Content-Length header and reads that many bytes from the socket. For PUT requests however, it only uses Trail, which is the data that has been already received while reading HTTP request headers. (This happens in the receive_headers function, which sends a length of 0 to the recv function, meaning that it won't wait for any specific amount of data.)
How much of the request body is received is going to depend on the size of the headers, as well as the way the client sends the request. If for example the client first sends the headers in one network packet, and then the request body in the next network packet, ejabberd wouldn't pick up the request body at all.
My application consumes some web service.
Segment of calling is below.
try
intf := getInterface(urlString);
request := TransaccionWS1.VentaDispositivoConvenioWSINTO.Create;
// here request field are initiated
//
//
AddToLogFile(format('Transaction Send: tid=%s authid=%s prod=%s',
[request.idExterno, request.nroReserva, elem.codProducto]), log_debug);
rs := intf.ventaDispositivoConvenio(request);
AddToLogFile(format('Transaction Recv: OK=%d result=%s auth_result=%s ' +
'descr=%s ticketnr=%s amount=%s text=%s',
[ord(rs.OK), rs.codigoRetorno, rs.codigoAutorizacion, rs.descripcionRetorno,
rs.nroTicket, rs.importeTicket, rs.textoLegal]), log_debug);
except
on e:exception do begin
AddToLogFile(format('**** Transaction: %s', [e.message]), log_exceptions);
raise;
end
end;
In general it is working ok
But sometimes i have a problem
I can see in log 'Transaction Send' but cannot see no 'Transaction Recv' and no exception.
Another thing i cannot explain, sometimes i see in log
03/01/2014 14:32:35.453 Transaction Send: tid=266996 authid=0000001958472 prod=86
03/01/2014 14:36:09.046 **** Transaction: The connection with the server was reset
Here exception raised after 4 minutes, while client use default timeouts values 30 seconds
May be someone has direction where to search?
You are assuming that your code is wrong, but maybe it's environmental? Consume the WSDL with SoapUI and run some tests to see if the webservice is stable and reachable.
i am using the GL865-DUAL GPRS module from Telit.
I'm trying to set up a HTTP POST request to a website with my location variables.
I am able to set up a working GPRS connection wit h the provider (got ip adres) but at the post at-command it goes wrong,
this is my command set:
"AT" //response: OK //build in delay of 5 seconds
Delay after each AT command set to 400miliseconds
"AT+CGMR //response: 16.00.152 OK
"AT#QSS?" //response: #QSS:0,1 OK
"AT#QSS=?" // response #QSS: (0-2) OK
"AT+CMEE=1" //response: OK
"AT+CMEE?" // response: +CMEE: 1
"AT+CPIN?" // response: +CPIN: READY OK
"AT+COPS?" // response: +COPS: 0,0,"PROXIMUS" OK
"AT+CSQ" // response: +CSQ: 20
"AT+cgatt=1" // response: OK
"AT+CGDCONT=1, \"IP\",\"internet.proximus.be\"" // response: OK // double quotes in c are expressed as \"
"AT+CGDCONT?" // response: +CGDCONT: 1,"IP","internet.proximus.be","",0,0 OK
"AT#SGACT?" // response: #SGACT: 1,0 OK
"AT#SCFG=?" //#SCFG: (1-6,(0-5),(0-1500),(0-65535),(10-1200),(0-255) OK
"AT#SCFG=1,1,300,90,600,50" // response: OK
"AT#SGACT?" //response: #SGACT: 1,0
"AT#SGACT = 1,1" //response: #SGACT: 178,144.233.116 OK
"AT#HTTPCFG=1,\"https://www.google.be/\",80,0,,,0,120,1" // response: OK
"AT#HTTPSND=1,0,\"search?q=yo\",4,\"1:charset=ISO-8859-1\"test" // response: CME Error 4
What am i doing wrong and is it possible to give a working example ?
Note: no Pin is required for the SIM card and no APN user and password is needed for my case.
Folowing documents could be helpful:
http://www.gaw.ru/pdf/DIA_Telecom/80000ST10028_Easy%20GPRS%20User%20Guide_r1.pdf
http://www4.telit.com/module/infopool/download.php?id=542
Thanks a lot!
Try removing the https:// and the trailing /. #HTTPCFG asks for a hostname or IP address, not a url.
I see two problems with your commands:
Your profile ID for HTTPCFG and HTTPSND don't match.
I think you need double quotes in your password and username fields
for HTTPCFG.
After AT#HTTPSND, the modem replies with >>> indicating that you need to supply Your data. The "test" at the end of that line shouldn't be there, it should be after a delay. you can try specifying just 1 for plain text and not the whole charset. Posting to google?
I'm trying to build a websocket server on Delphi6 using the draft hixie-76 and i have a problem with the handshake.
The md5 fingerprint i get with the three parts does not seem to be correct when i try it, but when i use the same algorythm with the exemple given in the protocole spec i get the good md5 response...
I'm processing like this, transform the number found in key1 divided by the number of spaces in a 32 bits word, same with key2 and finally adding the last 8 bytes (key3) to get a 128 bits string which i use as md5 entry.
using 155712099, 173347027 for key1 and key2 and 'Tm[K T2u' for key3, i get the correct md5 fingerprint and so i don't understand why this algo won't give a correct fingerprint to the client
here is an exemple of what i receive :
GET / HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Host: localhost:8018
Origin: null
Sec-WebSocket-Key1: 4 102(2 6U 2 3 18
Sec-WebSocket-Key2: 69V86`6t)e 0 2 42
M]Rzÿõ&
and the handshake i give in response
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: null
Sec-WebSocket-Location: ws://localhost:8018/
µ&Mq˜8èõÙZÙ,hœi
Maybye there's another probleme with my response but it reall seems that i have a problem with my md5 fingerprint.
Does anyone see where my mistake is??
Thanks in advance for your help
Update
I have seen this unit but unless i'm very bad at reading, the handshake part of this class does not calculate any md5 sum, i think it uses an older version of the protocol and not the current (76)
When i look at the following code i see that the answer is written without any md5 response.
` try
// Read request headers
HandshakeRequest := TWebSocketRequest.Create(ServerConnection);
// Send response headers
ServerConnection.WriteLn('HTTP/1.1 101 Web Socket Protocol Handshake');
ServerConnection.WriteLn('Upgrade: WebSocket');
ServerConnection.WriteLn('Connection: Upgrade');
ServerConnection.WriteLn('WebSocket-Origin: ' + HandshakeRequest.Origin);
ServerConnection.WriteLn('WebSocket-Location: ws://' + HandshakeRequest.Host + '/');
// End handshake
ServerConnection.WriteLn;
ServerConnection.WriteLn;
HandshakeResponseSent := True;
except
on E: TWebSocketHandshakeException do
begin
// Close the connection if the handshake failed
ServerConnection.Disconnect;
end;`
Thanks again
Update 2011 04 14
I have finally found where the problem was...
i was building my response like that :
resp := [...] +'Sec-WebSocket-Origin: '+ origin + #13#10 +
#13#10#13#10 +
md5response;
so there was 3 0x0D 0x0A instead of 2 before the md5 fingerprint ...
Since i cannot answer my own question i won't be able to mark it solve but it is! :)
There exists a websocket class in google code for Delphi that might give you the answer:
http://code.google.com/p/delphiws/source/browse/trunk/source/uWebSocket.pas?r=4
How i can determine the size in bytes of a remote file hosted in the web, before download it, using Delphi?
Thanks In advance.
You could use Indy.
First include IdHTTP.
You can retrieve the size this way:
procedure TFormMain.Button1Click(Sender: TObject);
var
Http: TIdHTTP;
begin
Http := TIdHTTP.Create(nil);
try
Http.Head('http://live.sysinternals.com/ADExplorer.exe');
ShowMessage(IntToStr(Http.Response.ContentLength));
finally
Http.Free;
end;
end;
Short answer: use the HTTP HEAD command, available in the TIdHttp component of Indy Delphi.
Details:
HTTP protocol defines a HEAD method.
9.4 HEAD
The HEAD method is identical to GET
except that the server MUST NOT return
a message-body in the response. The
metainformation contained in the HTTP
headers in response to a HEAD request
SHOULD be identical to the information
sent in response to a GET request.
This method can be used for obtaining
metainformation about the entity
implied by the request without
transferring the entity-body itself.
This method is often used for testing
hypertext links for validity,
accessibility, and recent
modification.
The response to a HEAD request MAY be
cacheable in the sense that the
information contained in the response
MAY be used to update a previously
cached entity from that resource. If
the new field values indicate that the
cached entity differs from the current
entity (as would be indicated by a
change in Content-Length, Content-MD5,
ETag or Last-Modified), then the cache
MUST treat the cache entry as stale.
HEAD Asks for the response identical to the one that would correspond to a GET request, but without the response body, retrieving the complete response headers, without the entire content.
The HTTP response headers retrieved are documented in List of HTTP headers on Wikipedia.
http://en.wikipedia.org/wiki/List_of_HTTP_headers
HTTP Headers form the core of an HTTP request,
and are very important in an HTTP response.
They define various characteristics of the data
that is requested or the data that has been provided.
The headers are separated from the request or
response body by a blank line. HTTP headers
can be near-arbitrary strings, but only some
are commonly understood.
One of the headers that is always present for a valid URL to retrieve a content is
the Content-Length header.
14.13 Content-Length
The Content-Length entity-header field indicates the
size of the entity-body, in decimal number of OCTETs,
sent to the recipient or, in the case of the HEAD method,
the size of the entity-body that would have been sent
had the request been a GET.
Content-Length = "Content-Length" ":" 1*DIGIT
An example is
Content-Length: 3495
Applications SHOULD use this field to indicate the
transfer-length of the message-body, unless this is
prohibited by the rules in section 4.4.
Any Content-Length greater than or equal to zero is a
valid value. Section 4.4 describes how to determine
the length of a message-body if a Content-Length is not given.
Note that the meaning of this field is significantly
different from the corresponding definition in MIME,
where it is an optional field used within the
"message/external-body" content-type. In HTTP,
it SHOULD be sent whenever the message's length
can be determined prior to being transferred,
unless this is prohibited by the rules in section 4.4.
From Delphi, drop a TIdHttp component to your form. And paste the following code in one of your delphi event process methods.
var
url: string; // must contain a fully qualified url
contentLength: integer;
begin
....
contentLength:=0;
try
Idhttp1.Head(url);
contentLength:=idhttp1.response.ContentLength;
except end;
....
Be aware that not ALL servers will return a valid content size for a head request. If the content length = 0, then you will ONLY know if you issue a GET request. For example the HEAD request against the Google logo returns a 0 content-length, however a GET returns the proper length, but also retrieves the image. Some servers will return content-length as the length of the packet following the header.
You can use Synapse to get at this information also. Note that the data is transfered, but the buffer is thrown away. This is a much more reliable method, but at the cost of additional bandwidth.
var
HTTP : tHTTPSend;
begin
HTTP := THTTPSend.Create;
try
HTTP.HTTPMethod('GET',url);
DownloadSize := HTTP.DownloadSize;
finally
HTTP.Free;
end;
end;