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
Diff: AMMPC/axHTTP.c
- Revision:
- 0:65004368569c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AMMPC/axHTTP.c Tue Jul 01 21:31:54 2014 +0000 @@ -0,0 +1,460 @@ +#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; +} + + + + + +