Axeda Corp
/
AxedaGo-ubloxC027
Axeda demo software for u-blox C027 (GSM)
AMMP/axHTTP.c
- Committer:
- AxedaCorp
- Date:
- 2014-08-11
- Revision:
- 1:ff6d8adaf6b9
- Parent:
- 0:a725e8eab383
File content as of revision 1:ff6d8adaf6b9:
#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; }