HTTP POST request


#1

I am trying trying to use HTTP POST to send data to our Vodafone server. I am supposed to send it in name/value pairs. We have two pairs(parameters) on our website date_time and temp. Please find my code below:

const ascii * HTTP_STR_URL = “http://weather.vodafonernd.com/post.php”;

static void http_ClientTestDataHandler( wip_event_t *ev, void ctx)
{
ascii tmpbuf[160];
int BytesWritten, code;
s32 status;
ascii info[50];
/
How many bytes of [tmpbuf] have already been sent. */
static int offset = 0;
s16 m,n,p,w;

m = (s16) GPIO26info_t.TenMinTemp * 10; // Decimal precision: 1 digit
n = (GPIO26info_t.TenMinTemp * 10 ) - m; // Decimal precision: 1 digit

p = (s16) GPIO26info_t.TenMinHum * 10; // Decimal precision: 1 digit
w = (GPIO26info_t.TenMinHum * 10 ) - p; // Decimal precision: 1 digit

wm_sprintf(tmpbuf, “date_time=%04lu-%02lu-%02lu%02lu:%02lu:%02lu&temp=%d.%01d”,
GPStimedate_t.year,
GPStimedate_t.month,
GPStimedate_t.day,
GPStimedate_t.hour,
GPStimedate_t.minute,
GPStimedate_t.seconds,
(s16)GPIO26info_t.TenMinTemp, n);

switch(ev->kind)
{
case WIP_CEV_OPEN:
TRACE(( 4, “http_ClientTestDataHandler: WIP_CEV_OPEN\n” ));
adl_atSendResponsePort ( ADL_AT_RSP, ADL_PORT_UART1, “\r\nhttp_ClientTestDataHandler: Start\r\n”);
break;

case WIP_CEV_READ:
adl_atSendResponsePort ( ADL_AT_RSP, ADL_PORT_UART1, “\r\nhttp_ClientTestDataHandler: WIP_CEV_READ\r\n”);
wip_getOpts(http_ClientTestCtx.DataChannel, WIP_COPT_HTTP_STATUS_CODE, &code, WIP_COPT_END);
wm_sprintf( info, “\r\nHTTP Status code: %d\r\n”, code);
adl_atSendResponsePort ( ADL_AT_RSP, ADL_PORT_UART1, info);
if (code == 200){
wip_close( http_ClientTestCtx.DataChannel);
wip_close( http_ClientTestCtx.CnxChannel);
}
break;

case WIP_CEV_WRITE:
      TRACE(( 4, "http_ClientTestDataHandler: WIP_CEV_WRITE\n" ));
      adl_atSendResponsePort ( ADL_AT_RSP, ADL_PORT_UART1, "\r\nhttp_ClientTestDataHandler: WIP_CEV_WRITE\r\n");

                 BytesWritten = wip_write( http_ClientTestCtx.DataChannel, tmpbuf, sizeof(tmpbuf)-offset);
      if(BytesWritten < 0)
      {/* error */
      wip_debug( "HTTP write error %i\n", BytesWritten);
      adl_atSendResponse ( ADL_AT_UNS, "\r\nwip_write error\r\n" );
	  return;
      }
      offset += BytesWritten; /* Update the number of bytes sent. */
      if( offset == sizeof( tmpbuf)) { /* All of [buffer] has been sent */
          TRACE(( 4, "http_ClientTestDataHandler: bytes %d written\n", offset ));
          wm_sprintf( info, "\r\nhttp_ClientTestDataHandler: %d bytes written\r\n", offset);
          adl_atSendResponsePort ( ADL_AT_RSP, ADL_PORT_UART1, info);
      }
     wip_shutdown( http_ClientTestCtx.DataChannel,FALSE,TRUE);

  break;

case WIP_CEV_PEER_CLOSE:
	TRACE(( 4, "http_ClientTestDataHandler: WIP_CEV_PEER_CLOSE\n" ));
	adl_atSendResponse ( ADL_AT_UNS, "\r\nhttp_ClientTestDataHandler: Done\r\n" );

	      // end of data
	      // show response information
	      if( wip_getOpts( ev->channel,
	            WIP_COPT_HTTP_STATUS_CODE, &status,
	            WIP_COPT_HTTP_STATUS_REASON, tmpbuf, sizeof(tmpbuf),
	            WIP_COPT_END) == OK) {
	        ascii sbuf[16];
	        adl_atSendResponse ( ADL_AT_UNS, "http_ClientTestDataHandler: Status=" );
	        wm_sprintf( sbuf, "%d", status);
	        adl_atSendResponse ( ADL_AT_UNS, sbuf);
	        adl_atSendResponse ( ADL_AT_UNS, "\r\nhttp_ClientTestDataHandler: Reason=\"" );
	        adl_atSendResponse ( ADL_AT_UNS, tmpbuf);
	        adl_atSendResponse ( ADL_AT_UNS, "\"\r\n" );
	        TRACE(( 4, "http_ClientTestDataHandler: Status=%d\n", status));
	        TRACE(( 4, "http_ClientTestDataHandler: Reason=\"%s\"\n", tmpbuf));
	      }
	      if( wip_getOpts( ev->channel,
	            WIP_COPT_HTTP_HEADER, "content-type", tmpbuf, sizeof(tmpbuf),
	            WIP_COPT_END) == OK) {
	        TRACE(( 4, "http_ClientTestDataHandler: Content Type=\"%s\"\n", tmpbuf));
	      }
	      TRACE(( 4, "http_ClientTestDataHandler: Response Length=%d bytes\n",
	              pHttpClientCtx->dataLength ));

	      // data channel must be closed
	      wip_close( ev->channel);

  break;

case WIP_CEV_ERROR:
  TRACE(( 2, "http_ClientTestDataHandler: WIP_CEV_ERROR %d\n",
          ev->content.error.errnum));
  //adl_atSendResponse ( ADL_AT_UNS, "http_ClientTestDataHandler: ERROR\r\n" );
  adl_atSendResponsePort ( ADL_AT_RSP, ADL_PORT_UART1, "\r\nhttp_ClientTestDataHandler: ERROR\r\n");
  // connection to server broken
  wip_close( ev->channel);

  break;

default:
  TRACE(( 2, "http_ClientTestDataHandler: unexpected event: %d\n",
          ev->kind));
  adl_atSendResponsePort ( ADL_AT_RSP, ADL_PORT_UART1, "\r\nunexpected event\r\n");
  break;

}
}

static s32 http_Client(void)
{
s32 ret = 0;

// HTTP Session creation
// ---------------------------
http_ClientTestCtx.CnxChannel = wip_HTTPClientCreateOpts(
                                    NULL,  // no handler
                                    NULL,  // no context

                                    // default headers
                                    WIP_COPT_HTTP_HEADER, "User-Agent", "HTTP/1.1",
                                    WIP_COPT_END);

  if (http_ClientTestCtx.CnxChannel == NULL)
  {
     TRACE(( 2, "cannot create http session channel\n" ));
     //adl_atSendResponse ( ADL_AT_UNS, "cannot create http session channel\r\n" );
     adl_atSendResponsePort ( ADL_AT_RSP, ADL_PORT_UART1, "\r\ncannot create http session channel\r\n");
     ret = -1;
  }
  else {
	  adl_atSendResponsePort ( ADL_AT_RSP, ADL_PORT_UART1, "\r\nhttp session channel created\r\n");


     // HTTP POST command
      		    http_ClientTestCtx.DataChannel = wip_getFileOpts(
      		                                         http_ClientTestCtx.CnxChannel,  // session channel
      		                                         HTTP_STR_URL,                   // URL to receive the data
      		                                         http_ClientTestDataHandler,     // data handler
      		                                         &http_ClientTestCtx,            // context
      		                                         WIP_COPT_HTTP_METHOD,  WIP_HTTP_METHOD_POST,
      		                                         // request headers
      		              WIP_COPT_HTTP_HEADER, "Content-Type", "application/x-www-form-urlencoded",
      		                                         WIP_COPT_HTTP_HEADER, "Content-Length", 160,
      		                                         WIP_COPT_HTTP_HEADER, "Accept",          "text/html",	      		                                         	    WIP_COPT_END);

      		    if (http_ClientTestCtx.DataChannel == NULL)
      		    {
      		      TRACE(( 2, "cannot create http data channel\n" ));
      	adl_atSendResponsePort ( ADL_AT_RSP, ADL_PORT_UART1, "\r\ncannot create http data channel\r\n");
      		      wip_close( http_ClientTestCtx.CnxChannel);
      		     // ret =-1;
      		    }
      		    else
      adl_atSendResponsePort ( ADL_AT_RSP, ADL_PORT_UART1, "\r\nHTTP data channel created\r\n");
           }
  		    return(ret);

}

I get the following traces/responses and the data is not posted on our server.

http session channel created
[HTTP] new request GET weather.vodafonernd.com/post.php HTTP/1.1 @ 180ed12020
[HTTP] connect to host: weather.vodafonernd.com:80
HTTP data channel created
http_ClientTestDataHandler: Start
http_ClientTestDataHandler: WIP_CEV_WRITE
http_ClientTestDataHandler: 160 bytes written
http_ClientTestDataHandler: WIP_CEV_READ
HTTP Status code: 400

The status code 400 means my request is bad or has a wrong syntax. Please what is wrong with my syntax? how should i sent the reqeust message so that the server receives the name/value pairs ?


#2

I don’t know if this header id is good: WIP_COPT_HTTP_HEADER, “Content-Length”, 160, - maybe you should replace 160 to a string.


#3

Hiya,

A : (colon) is not permitted in a POST field. This character also needs to be URL encoded ( %3A ). However, a - (dash) seems to be OK.

I’ve done a quick count of your data request:

[10] date_time=
[ 4] %04lu
[ 1] -
[ 2] %02lu
[ 2] %02lu
[ 1] :
[ 2] %02lu
[ 6] &temp=
[??] %d
[ 1] .
[ 1] %01d

This adds up to 30 characters (not counting [??] and not expanding the colon into %3A).
The Content-Length: has to be the exact length of the URL encoded data in the request…or the server will barf on your data.
Note that the field %d is going to be an indeterminate length, depending on the value of your variable - which will make using a fixed value for your header a little bit harder. You are probably better using %04d to ensure that the value is always the same length (as you did with the date and time fields).

My final comment is that you are probably better building the content buffer before you start the HTTP POST event, rather than in the top of the event handler as you are doing at the moment. That way, you can build your content header along the following lines:

static s32 http_Client( void )
{
    ascii tmpbuf[160];
    ascii contentHdrBuf[10];

    // set up session etc

    // create outgoing data buffer

    wm_sprintf(tmpbuf, "");   // as per your existing code

    // create content length header

    wm_sprintf(contentHdrBuf, "%d", wm_strlen(tmpbuf));

    // create POST request
    http_ClientTestCtx.DataChannel = wip_getFileOpts(
        http_ClientTestCtx.CnxChannel,                                  // session channel
        HTTP_STR_URL, // URL to receive the data
        http_ClientTestDataHandler,                                       // data handler
        &http_ClientTestCtx,                                                 // context
        WIP_COPT_HTTP_METHOD, WIP_HTTP_METHOD_POST,
                                                                                        // request headers
        WIP_COPT_HTTP_HEADER, "Content-Type", "application/x-www-form-urlencoded",
        WIP_COPT_HTTP_HEADER, "Content-Length", contentHdrBuf,
        WIP_COPT_HTTP_HEADER, "Accept", "text/html", 
        WIP_COPT_END);

    // continue processing

Hope this helps.

ciao, Dave

P.S. Please use the

[code]
tags next time you insert code into a forum post. It keeps all your formatting - and makes it easier for the rest of us to read :smiley: .


#4

This just caught me out - the 160 is missing double quotes.

So the line should be

WIP_COPT_HTTP_HEADER, "Content-Length", "160"