Axeda Ready Demo for Freescale FRDM-KL46Z as accident alert system

Dependencies:   FRDM_MMA8451Q KL46Z-USBHost MAG3110 SocketModem TSI mbed FATFileSystem

Fork of AxedaGo-Freescal_FRDM-KL46Z by Axeda Corp

AMMPC/axHTTP.c

Committer:
AxedaCorp
Date:
2014-07-02
Revision:
2:2f9019c5a9fc
Parent:
0:65004368569c

File content as of revision 2:2f9019c5a9fc:

#include "axHTTP.h"
#include "axStatusCodes.h"
#include "axConstants.h"
#include "ctype.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "axSettings.h"
#include "axTransport.h"

#define AX_HTTP_OK                  200
#define AX_HTTP_SYNTAX_INVALID      400     //The Request syntax is incorrect
#define AX_HTTP_UNAUTHORIZED        401     //You need permission to access that resource. Agent Authentication failure
#define AX_HTTP_FORBIDDEN           403     //You need permission to access that resource.
#define AX_HTTP_NOT_FOUND           404     //The resource was not found
#define AX_HTTP_REQ_INVALID         405     //Content type is invalid, should be application/json most of the time
#define AX_HTTP_CONTENT_INVALID     422     //The Request is valid syntactically but the content is invalid e.g. wrong instruction
#define AX_HTTP_SERVER_ERROR        500     //The server attempted to handle your request but a failure occurred; check the server logs.

#define HTTPKEY_GET         0
#define HTTPKEY_POST        1
#define HTTPKEY_PUT         2
#define HTTPKEY_PROTOCOL    3
#define HTTPKEY_CRLF        4


#define HTTPH_HOST          0
#define HTTPH_TYPE          1
#define HTTPH_LENGTH        2
#define HTTPH_CONNECTION    3
#define HTTPH_XCOUNT        4
#define HTTPH_CONTENTDIS    5
#define HTTPH_MULTIPART     6
#define HTTPH_FORMDATA      7
#define HTTPH_ACCEPT        8

#define HTTPR_TYPE          0
#define HTTPR_LENGTH        1
#define HTTPR_BODY_SEP      2
#define HTTPR_DELIMS        3

int http_debug=AX_FALSE;
int x_count=0;

int http_getResponse(HTTP_Transmission *response, ax_socket *source);

char *HTTP_KEY[]= {"GET", "POST", "PUT", "HTTP/1.1", "\r\n"};
char *HTTP_HEADER[] = { "Host: ", "Content-Type: ", "Content-Length: ", "Connection: close", "x-count: ", "Content-Disposition: ","multipart/form-data; boundary=", "form-data;", "Accept: */*"};
char *HTTP_RESP[] = { "Content-Type:", "Content-Length:", "\r\n\r\n", " \r\n"}; 

int http_send(HTTP_Transmission *request, char *host, int port, int secure, HTTP_Transmission *response){
  int retVal=AX_UNKNOWN;

  switch(request->operation) {
      case AX_HTTP_GET:
        retVal=http_send_get(request->resource, host, port, secure, response);
      break;
      case AX_HTTP_POST:
        retVal=http_send_post(request->resource, host, port, secure, &request->headers, request->body, request->body_length, response);
      break;
      case AX_HTTP_PUT:
              retVal=http_send_put(request->resource, host, port, secure, &request->headers, request->body, request->body_length, response);
      break;
      case AX_HTTP_MPOST:
        retVal=http_send_mpost(request->resource, host, port, secure, &request->headers, request->body, request->body_length, request->mpData, 1, response);
      break;
      }

  return retVal;
  }

int http_send_get(char *resource, char *host, int port, int secure, HTTP_Transmission *response) {
  int retVal=AX_UNKNOWN;

  if(!resource||!host||!response) { return AX_ARGNULL; }
  if((port < 0)||(port>65536)) { return AX_NET_PORT_INVALID; }
  int sz=strlen(HTTP_KEY[HTTPKEY_GET])+strlen(resource)+strlen(HTTP_KEY[HTTPKEY_PROTOCOL])+strlen(HTTP_HEADER[HTTPH_HOST])+strlen(host)+13+6+strlen(HTTP_HEADER[HTTPH_CONNECTION])+strlen(HTTP_HEADER[HTTPH_ACCEPT]); //+6 adds space for extra CRLFs, spaces, and null terminator

  ax_socket sock;

  retVal=net_socketInit(&sock);
  retVal=net_socketOpen(&sock, host, port, secure);
  if(retVal!=AX_OK){
      return retVal;
      }

  char *buff=(char *)malloc(sizeof(char)*sz);
  int wrtSz=snprintf(buff, sz, "%s %s %s%s%s%s:%d%s%s%s%s", HTTP_KEY[HTTPKEY_GET], resource, HTTP_KEY[HTTPKEY_PROTOCOL], HTTP_KEY[HTTPKEY_CRLF], HTTP_HEADER[HTTPH_HOST], host, port, HTTP_KEY[HTTPKEY_CRLF], HTTP_HEADER[HTTPH_CONNECTION], HTTP_KEY[HTTPKEY_CRLF], HTTP_KEY[HTTPKEY_CRLF]);

  if(wrtSz>sz) { printDebug("http_send_get(): Buffer allocated for header was too small, truncated"); } 
  retVal=net_socketWrite(&sock, buff, sz);
  retVal=net_socketFlush(&sock);

  retVal=http_getResponse(response, &sock);
  if(retVal==AX_HTTP_OK) { retVal=AX_OK; }

  net_socketClose(&sock);
  free(buff);
  return retVal;
  }

int http_send_put(char *resource, char *host, int port, int secure, HTTP_Headers *headers, char *data, int data_sz, HTTP_Transmission *response) {
  int retVal=AX_UNKNOWN;

  if(!resource||!host||!response) { return AX_ARGNULL; }
  if((port < 0)||(port>65536)) { return AX_NET_PORT_INVALID; }
  if((!data)&&(data_sz!=0)) { return AX_CONFLICTING_ARG; }

  ax_socket sock;

  retVal=net_socketInit(&sock);
  retVal=net_socketOpen(&sock, host, port, secure);
  if(retVal!=AX_OK){ //if a failure occurred bail out. failures here would be that a port is not free
    return retVal;
    }
  printDebug("Attempting to create headers");
   char *header=NULL;
   header=createHeaders(header, HTTPKEY_PUT, resource, HTTPKEY_PROTOCOL, host, headers->contentType, data_sz, x_count); //returns a malloc'd string with the headers

  retVal=net_socketWrite(&sock, header, strlen(header));
  if(retVal!=AX_OK){ //if a failure occurred bail out. failures here would be that a port is not free
      goto cleanup;
      }
  retVal=net_socketWrite(&sock, data, data_sz);
  net_socketFlush(&sock);
  if(retVal!=AX_OK) {
     retVal=AX_NET_ERR_DATA_WRITE;
     goto cleanup;
     }

  retVal=http_getResponse(response, &sock);
  if(retVal==AX_HTTP_OK) { retVal=AX_OK; }

  x_count++;
   goto cleanup;


cleanup:
  net_socketClose(&sock);
  free(header);
  return retVal;
}



int http_send_post(char *resource, char *host, int port, int secure, HTTP_Headers *headers, char *data, int data_sz, HTTP_Transmission *response){
  int retVal=AX_UNKNOWN;

  if(!resource||!host||!response) { return AX_ARGNULL; }
  if((port < 0)||(port>65536)) { return AX_NET_PORT_INVALID; }
  if((!data)&&(data_sz!=0)) { return AX_CONFLICTING_ARG; }

  ax_socket sock;

  retVal=net_socketInit(&sock);
  retVal=net_socketOpen(&sock, host, port, secure);
  if(retVal!=AX_OK){ //if a failure occurred bail out. failures here would be that a port is not free
    return retVal;
    }
  printDebug("Attempting to create headers");
   char *header=NULL;
   header=createHeaders(header, HTTPKEY_POST, resource, HTTPKEY_PROTOCOL, host, headers->contentType, data_sz, x_count); //returns a malloc'd string with the headers

  retVal=net_socketWrite(&sock, header, strlen(header));
  if(retVal!=AX_OK){ //if a failure occurred bail out. failures here would be that a port is not free
      goto cleanup;
      }
  retVal=net_socketWrite(&sock, data, data_sz);
  net_socketFlush(&sock);
  x_count++;
  printDebug("Transmission sent, Waiting for response\n");


  retVal=http_getResponse(response, &sock);
  if(retVal==AX_HTTP_OK) { retVal=AX_OK; }

   goto cleanup;

cleanup:
  net_socketClose(&sock);
  free(header);
  return retVal;
  }

int http_send_mpost(char *resource, char *host, int port, int secure, HTTP_Headers *headers, char *data, int data_sz, HTTP_Part *files, int part_ct, HTTP_Transmission *response) {
    int retVal=AX_UNKNOWN;
 //   char xcount_tmp[10];
//    char clength_tmp[10];
    int boundary_sz=10;
    int body_sz=0;
    int hint_sz=0;
    char *hint=NULL;
	char *header=NULL;
    ax_socket sock;

      if(!resource||!host||!response) { return AX_ARGNULL; }
    if((port < 0)||(port>65536)) { return AX_NET_PORT_INVALID; }
    if((!data)&&(data_sz!=0)) { return AX_CONFLICTING_ARG; }
 //Assemble body Parts
    char *fileargs=NULL;
    int file_arg_len=strlen(files->file_name)+51;
    fileargs=(char *)malloc(sizeof(char)*file_arg_len);
    int wrtfarg=snprintf(fileargs, file_arg_len, "name=\"file\"; filename=\"%s\"\r\nContent-Type: text/plain", files->file_name);
    if(wrtfarg>file_arg_len) { printDebug("http_send_mpost(): Buffer allocated for file arguments was too small, truncated"); }
    if(files->hint!=NULL)
        {
        hint_sz=strlen(files->hint)+18;//+1 for terminating char
        hint=(char *)malloc(sizeof(char)*hint_sz);
        int wrthint=snprintf(hint, hint_sz, "name=\"hint\"\r\n\r\n%s\r\n", files->hint);
        if(wrthint>hint_sz) { printDebug("http_send_mpost(): Buffer allocated for hint was too small, truncated"); }
        }
//body size calculation here
  //Boundary: --<boundary>
    body_sz=body_sz+2+boundary_sz;   
  //adding body ---for mparts
    if(data_sz>0){
      body_sz=body_sz+36+data_sz+boundary_sz;  
      }
  //Add Hint     Content-Disposition: form-data;name="<hint>"\r\n--<boundary>\r\n
    if(files->hint!=NULL){
      body_sz=body_sz+38+strlen(hint)+boundary_sz;  
      }
    if(files->data_sz>0) {
      body_sz=body_sz+38+strlen(fileargs)+files->data_sz;
      }
    body_sz=body_sz+8+boundary_sz;

//get a boundary for the multipart
    char *boundary=(char *)malloc(sizeof(char)*boundary_sz);
    http_getBoundary(boundary, boundary_sz);
//convert the data size integer into a string
 //  int wrtCLen=snprintf(clength_tmp, 10, "%d", body_sz);
 //   if(wrtCLen>10) { printDebug("http_send_mpost(): Buffer allocated for clength_tmp was too small, truncated"); }
    //Add operation line

    printDebug("Attempting to create headers");

//Create Content Type 
	 int cTypeSz=0;
	 cTypeSz=strlen(HTTP_HEADER[HTTPH_MULTIPART])+strlen(boundary)+1;
	 char *contentType=(char *)calloc(cTypeSz, sizeof(char));       
	 int wrt_ctype=snprintf(contentType, cTypeSz, "%s%s", HTTP_HEADER[HTTPH_MULTIPART], boundary);
	 if(wrt_ctype>cTypeSz) { printDebug("http_send_mpost(): Buffer allocated for contentType was too small, truncated");}
//Get the headers
     header=createHeaders(header, HTTPKEY_POST, resource, HTTPKEY_PROTOCOL, host, contentType, body_sz, x_count); //returns a malloc'd string with the headers
	 free(contentType); //we're done with the string we used to cat the values
//Start to send the data
	retVal=net_socketInit(&sock);
    retVal=net_socketOpen(&sock, host, port, secure);
    if(retVal!=AX_OK){ //if a failure occurred, bail out. A failure here would indicate that a port is closed, or the network is not available.
      return retVal;
      }
//Write the headers
    retVal=net_socketWrite(&sock, header, strlen(header));
      if(retVal!=AX_OK){ goto cleanup; }

   //write the body...
   //start boundary
      retVal=net_socketWrite(&sock, "--", 2);
      retVal=net_socketWrite(&sock, boundary, boundary_sz);
      retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
   //1st section -uses the data in body if specified
    if(data_sz>0){
      retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_CONTENTDIS], 21);
      retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_FORMDATA], 11);
      retVal=net_socketWrite(&sock, data, data_sz); //Write body data, the fields and values
      retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
      retVal=net_socketWrite(&sock, "--", 2);
      retVal=net_socketWrite(&sock, boundary, boundary_sz);
      }
    if(files->hint!=NULL){
       retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_CONTENTDIS], 21);
       retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_FORMDATA], 11);
       retVal=net_socketWrite(&sock, hint, hint_sz); //Write body data, the fields and values
       retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
       retVal=net_socketWrite(&sock, "--", 2);
       retVal=net_socketWrite(&sock, boundary, boundary_sz);
       retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
       }
    if(files->data_sz>0) {
        retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_CONTENTDIS], 21);
        retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_FORMDATA], 11);
        retVal=net_socketWrite(&sock, fileargs, file_arg_len);
        retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
        retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
        retVal=net_socketWrite(&sock, (char *)files->data, files->data_sz);
        retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
        }
      retVal=net_socketWrite(&sock, "--", 2);
      retVal=net_socketWrite(&sock, boundary, boundary_sz);
      retVal=net_socketWrite(&sock, "--", 2);
      retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
      retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);


    net_socketFlush(&sock);
    x_count++;
    retVal=http_getResponse(response, &sock);
    if(retVal==AX_HTTP_OK) { retVal=AX_OK; }

  cleanup:
   net_socketClose(&sock);
   free(header);
   free(hint);
   free(fileargs);
   free(boundary);
   return retVal;
  }

void http_add_mpart(HTTP_Transmission *request, char *file_name, unsigned char *data, int file_sz) {
 //For future expansion.
}

//Return Handling
HTTP_Transmission *http_parse(HTTP_Transmission *response, char *data){
printDebug("Starting parse of ");
printDebug(data);

    char clength[7];
    int reqSize=0;
    char *temp=NULL;
    char *bodyStart=NULL;
    response->body_length=0;
    response->response_code=-1; //indicate that no response code has been recieved(yet)

    reqSize=strlen(data);
    if(reqSize<=12) { printDebug("No Body included"); }
    else { printDebug("body present" );
    bodyStart=strstr(data, HTTP_RESP[HTTPR_BODY_SEP]);
    if(bodyStart==NULL) { printDebug("D'oh! Couldn't parse for body\n"); }
    else {
	 int body_length=strlen(bodyStart)-4; //don't count the extra \r\n\r\n
         response->body_length=body_length;
         response->body=(char *)calloc(body_length+1, sizeof(char));
         snprintf(response->body, body_length+1, "%s", bodyStart+4); //the +4 gets rid of the preceeding \r\n\r\n
         }
    }

    temp = strtok(data, HTTP_RESP[HTTPR_DELIMS]);
    while (temp!=NULL) {

    if((strlen(temp)==3)&&(isdigit((int)temp[0]))&&(isdigit((int)temp[1]))&&(isdigit((int)temp[2]))) {
        response->response_code=atoi(temp); //convert the text response code to an int.
        }

    if(strcmp(temp, HTTP_RESP[HTTPR_TYPE])==0) {
        response->headers.contentType=strtok(NULL, HTTP_RESP[HTTPR_DELIMS]);
        }
    if(strcmp(temp, HTTP_RESP[HTTPR_LENGTH])==0){
        temp=strtok(NULL, HTTP_RESP[HTTPR_DELIMS]);
        strcpy(clength, temp);
    response->body_length=atoi(clength);
    if(response->body_length<=0) {
         response->body_length=strlen(bodyStart+4);
          }
        }

    temp=strtok(NULL, HTTP_RESP[HTTPR_DELIMS]);
    }

    return response;
    }

int http_getResponse(HTTP_Transmission *response, ax_socket *source){
    int retVal=AX_UNKNOWN;
    char *responseTxt=NULL;
     responseTxt=(char *)calloc(AX_NET_BUFF_S, sizeof(char));
     int length=0;
     response->response_code=0;
     retVal=net_socketRead(source, 300, (unsigned char *)responseTxt, AX_NET_BUFF_S, &length);
     if(retVal==AX_OK) { printDebug("response received"); }
     else { printDebug("Response Timeout"); return AX_NET_ERR_TIMEOUT;}
     http_parse(response, (char *)responseTxt); 

     free(responseTxt);
    return response->response_code;
    }


//Supporting Methods
/***************************************************************************************************/
/*http_getBoundary()                                                                               */
/*                                                                                                 */
/*This method creates a unique string token that is used when creating mulitpart form transmissions*/
/*in HTTP. It will return a random sequence of letters and numbers.                                */
/***************************************************************************************************/
char *http_getBoundary(char *buff, int length){
    int ctr=0;
    if(buff==NULL) { return NULL; } //if no pointer was given to us give a nothing back.
    if(length<=0) {return NULL;} 
       int randNum=0;
       for(ctr=0; ctr<length; ctr++) {
       randNum=abs(randInt()%62);
           if(randNum<=10) {
		if(randNum==0) { randNum++; } //avoid using slashes in boundary, char 47
               buff[ctr]=randNum+47;
               }
           else if((randNum>10)&&(randNum<=36)) {
               buff[ctr]=(randNum-10)+64;
               }
           else {
               buff[ctr]=(randNum-37)+97;
               }
           if(buff[ctr]==32) {buff[ctr]=97; }
       }

    return buff;
    }

void zeroOutHTTPXmission(HTTP_Transmission *tgt){

	    tgt->operation=-1;
	    tgt->resource=NULL;
	    tgt->headers.contentType=NULL;
	    tgt->body=NULL;
	    tgt->body_length=0;
	    tgt->mpData=NULL;
	    tgt->response_code=-1;
	    tgt->secure=-1;
}

char *createHeaders(char *tgtBuff, int http_operation, char *resource, int httpver, char *hostname, char *contentType, int contentLength, int xCount) {
  int headerSz=4;  //we account for the closing CRLF CRLF here
  char clength_tmp[10];
  char xCount_tmp[10];
  int wrthdr=0;  
//convert the ints to strings so we can get an strlen on them
  snprintf(clength_tmp, 10, "%d", contentLength);
  snprintf(xCount_tmp, 10, "%d", xCount);

//String Size Calculations
  headerSz=headerSz+strlen(resource)+strlen(HTTP_KEY[http_operation])+strlen(HTTP_KEY[httpver])+5; //"POST  HTTP/1.1" there are 2 spaces and a CRLF in there as well., 1 for the null
  headerSz=headerSz+strlen(HTTP_HEADER[HTTPH_HOST])+strlen(hostname)+2;  //Host: <hostname>
  headerSz=headerSz+strlen(HTTP_HEADER[HTTPH_TYPE])+strlen(contentType)+2;  //Content-Type: <contentType>
  headerSz=headerSz+strlen(HTTP_HEADER[HTTPH_LENGTH])+strlen(clength_tmp)+2;  //Content-Length: <contentLength>
  headerSz=headerSz+strlen(HTTP_HEADER[HTTPH_CONNECTION])+2; 		      //Connection: Close
  if(xCount>0) {
    headerSz=headerSz+strlen(HTTP_HEADER[HTTPH_XCOUNT])+strlen(xCount_tmp)+2;	
   }

//String buffer creation  
  tgtBuff=(char *)calloc(headerSz, sizeof(char));
//Stuffin the buffer
  if((xCount>0)&&(http_debug==AX_TRUE)) {
     wrthdr=snprintf(tgtBuff, headerSz, "%s %s %s\r\n%s%s\r\n%s%s\r\n%s%s\r\n%s\r\n%s%s\r\n\r\n", HTTP_KEY[http_operation], resource, HTTP_KEY[httpver], HTTP_HEADER[HTTPH_HOST], hostname, HTTP_HEADER[HTTPH_TYPE], contentType, HTTP_HEADER[HTTPH_LENGTH], clength_tmp, HTTP_HEADER[HTTPH_CONNECTION], HTTP_HEADER[HTTPH_XCOUNT], xCount_tmp);
	}
  else {
     wrthdr=snprintf(tgtBuff, headerSz, "%s %s %s\r\n%s%s\r\n%s%s\r\n%s%s\r\n%s\r\n\r\n", HTTP_KEY[http_operation], resource, HTTP_KEY[httpver], HTTP_HEADER[HTTPH_HOST], hostname, HTTP_HEADER[HTTPH_TYPE], contentType, HTTP_HEADER[HTTPH_LENGTH], clength_tmp, HTTP_HEADER[HTTPH_CONNECTION]);   

     }
  if(wrthdr>headerSz) { printDebug("http_send_post(): Buffer allocated for header was too small, truncated"); }

return tgtBuff;
}