GDP group 24 node core

Dependencies:   EthernetInterface SDFileSystem mbed-rtos mbed snail MbedJSONValue

Committer:
Trumple
Date:
Tue Jan 13 21:30:18 2015 +0000
Revision:
12:daddfc44a0f5
Parent:
2:1cbb20dd1733
Child:
23:b57a47c7862a
Fix HTTP library to prevent hanging after making HTTP requests

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Trumple 1:27b35752c5d0 1 #include "mbed.h"
Trumple 1:27b35752c5d0 2 #include "http.h"
Trumple 1:27b35752c5d0 3 #include <string>
Trumple 1:27b35752c5d0 4 #include <vector>
Trumple 1:27b35752c5d0 5
Trumple 2:1cbb20dd1733 6 void http::connect()
Trumple 1:27b35752c5d0 7 {
Trumple 1:27b35752c5d0 8 #ifdef DEBUG
Trumple 1:27b35752c5d0 9 printf("[HTTP] Ethernet connecting...\r\n");
Trumple 1:27b35752c5d0 10 #endif
Trumple 1:27b35752c5d0 11
Trumple 1:27b35752c5d0 12 eth.init();
Trumple 1:27b35752c5d0 13 eth.connect();
Trumple 1:27b35752c5d0 14
Trumple 1:27b35752c5d0 15 #ifdef DEBUG
Trumple 1:27b35752c5d0 16 printf("[HTTP] Ethernet connected, IP: %s\r\n", eth.getIPAddress());
Trumple 1:27b35752c5d0 17 #endif
Trumple 1:27b35752c5d0 18 }
Trumple 1:27b35752c5d0 19
Trumple 1:27b35752c5d0 20 string http::get(string address, int port, string url, int replyTimeout)
Trumple 1:27b35752c5d0 21 {
Trumple 1:27b35752c5d0 22 #ifdef DEBUG
Trumple 2:1cbb20dd1733 23 printf("[HTTP] Sending GET request to %s:%i%s\r\n", address.c_str(), port, url.c_str());
Trumple 1:27b35752c5d0 24 #endif
Trumple 1:27b35752c5d0 25
Trumple 1:27b35752c5d0 26 TCPSocketConnection sock;
Trumple 1:27b35752c5d0 27 sock.connect(address.c_str(), port);
Trumple 1:27b35752c5d0 28
Trumple 1:27b35752c5d0 29 #ifdef DEBUG
Trumple 1:27b35752c5d0 30 printf("[HTTP] Connected to endpoint...\r\n");
Trumple 1:27b35752c5d0 31 #endif
Trumple 1:27b35752c5d0 32
Trumple 1:27b35752c5d0 33 string httpget = "GET " + url + " HTTP/1.1";
Trumple 1:27b35752c5d0 34 httpget += "\nHost: " + address + "\n\n";
Trumple 1:27b35752c5d0 35
Trumple 1:27b35752c5d0 36 //get a writable char* (I.E. not const char* returned by c_str), put it into a vector
Trumple 1:27b35752c5d0 37 vector<char> writable(httpget.begin(), httpget.end());
Trumple 1:27b35752c5d0 38 writable.push_back('\0');
Trumple 1:27b35752c5d0 39
Trumple 1:27b35752c5d0 40 sock.send_all(&writable[0], writable.size()-1);
Trumple 1:27b35752c5d0 41
Trumple 1:27b35752c5d0 42 string message = this->receiveFromSock(sock, replyTimeout);
Trumple 1:27b35752c5d0 43
Trumple 1:27b35752c5d0 44 sock.close();
Trumple 1:27b35752c5d0 45
Trumple 1:27b35752c5d0 46 return this->parse(message);
Trumple 1:27b35752c5d0 47 }
Trumple 1:27b35752c5d0 48
Trumple 1:27b35752c5d0 49 string http::post(string address, int port, string url, string jsonPayload, int replyTimeout)
Trumple 1:27b35752c5d0 50 {
Trumple 1:27b35752c5d0 51 #ifdef DEBUG
Trumple 2:1cbb20dd1733 52 printf("[HTTP] Sending POST request to %s:%i%s\r\n", address.c_str(), port, url.c_str());
Trumple 1:27b35752c5d0 53 #endif
Trumple 1:27b35752c5d0 54
Trumple 1:27b35752c5d0 55 TCPSocketConnection sock;
Trumple 1:27b35752c5d0 56 sock.connect(address.c_str(), port);
Trumple 1:27b35752c5d0 57
Trumple 1:27b35752c5d0 58 #ifdef DEBUG
Trumple 1:27b35752c5d0 59 printf("[HTTP] Connected to endpoint...\r\n");
Trumple 1:27b35752c5d0 60 #endif
Trumple 1:27b35752c5d0 61
Trumple 2:1cbb20dd1733 62 char buffer[20];
Trumple 2:1cbb20dd1733 63 sprintf(buffer, "%i", jsonPayload.size());
Trumple 2:1cbb20dd1733 64 string contentLengthStr = string(buffer);
Trumple 1:27b35752c5d0 65
Trumple 1:27b35752c5d0 66 string httppost = "POST " + url + " HTTP/1.1";
Trumple 1:27b35752c5d0 67 httppost += "\nHost: " + address;
Trumple 1:27b35752c5d0 68 httppost += "\nContent-Type: application/json";
Trumple 1:27b35752c5d0 69 httppost += "\nContent-Length: " + contentLengthStr;
Trumple 2:1cbb20dd1733 70 httppost += "\nAuthorization: Key 1";
Trumple 1:27b35752c5d0 71 httppost += "\n\n" + jsonPayload;
Trumple 1:27b35752c5d0 72
Trumple 1:27b35752c5d0 73 //to get a writable char* (I.E. not const char* returned by string.c_str), put it into a vector
Trumple 1:27b35752c5d0 74 vector<char> writable(httppost.begin(), httppost.end());
Trumple 1:27b35752c5d0 75 writable.push_back('\0');
Trumple 1:27b35752c5d0 76
Trumple 1:27b35752c5d0 77 sock.send_all(&writable[0], writable.size()-1);
Trumple 1:27b35752c5d0 78
Trumple 1:27b35752c5d0 79 string message = this->receiveFromSock(sock, replyTimeout);
Trumple 1:27b35752c5d0 80
Trumple 1:27b35752c5d0 81 sock.close();
Trumple 1:27b35752c5d0 82
Trumple 1:27b35752c5d0 83 return this->parse(message);
Trumple 1:27b35752c5d0 84 }
Trumple 1:27b35752c5d0 85
Trumple 1:27b35752c5d0 86 string http::receiveFromSock(TCPSocketConnection sock, int replyTimeout)
Trumple 1:27b35752c5d0 87 {
Trumple 1:27b35752c5d0 88 char buffer[1024];
Trumple 1:27b35752c5d0 89 int receiveByteCount;
Trumple 1:27b35752c5d0 90 string message;
Trumple 1:27b35752c5d0 91
Trumple 12:daddfc44a0f5 92 bool headersSet = false;
Trumple 12:daddfc44a0f5 93 int contentLength = -1;
Trumple 12:daddfc44a0f5 94 string responseBody;
Trumple 12:daddfc44a0f5 95
Trumple 12:daddfc44a0f5 96 string contentLengthNeedle = "Content-Length: ";
Trumple 12:daddfc44a0f5 97
Trumple 1:27b35752c5d0 98 while (true)
Trumple 1:27b35752c5d0 99 {
Trumple 1:27b35752c5d0 100 receiveByteCount = sock.receive(buffer, sizeof(buffer)-1);//spare a byte for null termination byte
Trumple 12:daddfc44a0f5 101
Trumple 12:daddfc44a0f5 102 //if the connection is closed by the remote client
Trumple 1:27b35752c5d0 103 if (receiveByteCount <= 0)
Trumple 1:27b35752c5d0 104 break;
Trumple 12:daddfc44a0f5 105
Trumple 1:27b35752c5d0 106 buffer[receiveByteCount] = '\0';
Trumple 1:27b35752c5d0 107 message += buffer;
Trumple 12:daddfc44a0f5 108
Trumple 12:daddfc44a0f5 109 //if the response header has been received and includes the required headers
Trumple 12:daddfc44a0f5 110 if (!headersSet && message.find("\r\n\r\n") != string::npos && message.find(contentLengthNeedle) != string::npos)
Trumple 12:daddfc44a0f5 111 {
Trumple 12:daddfc44a0f5 112 //headers have been fully received, ensure this check is not performed again
Trumple 12:daddfc44a0f5 113 headersSet = true;
Trumple 12:daddfc44a0f5 114 //end point of the "Content-Length: " string, beginning of the integer it specifies
Trumple 12:daddfc44a0f5 115 int cl = message.find(contentLengthNeedle) + contentLengthNeedle.size();
Trumple 12:daddfc44a0f5 116 //extract the content length from the header
Trumple 12:daddfc44a0f5 117 string length = message.substr(cl, message.find_first_of("\r\n", cl) - cl);
Trumple 12:daddfc44a0f5 118 contentLength = atoi(length.c_str());
Trumple 12:daddfc44a0f5 119 }
Trumple 12:daddfc44a0f5 120
Trumple 12:daddfc44a0f5 121 //if the headers have been set, extract the message body
Trumple 12:daddfc44a0f5 122 if (headersSet)
Trumple 12:daddfc44a0f5 123 responseBody = message.substr(message.find("\r\n\r\n"), contentLength);
Trumple 12:daddfc44a0f5 124
Trumple 12:daddfc44a0f5 125 //if the response body is of the expected length, we're done
Trumple 12:daddfc44a0f5 126 if (responseBody.size() >= contentLength)
Trumple 12:daddfc44a0f5 127 break;
Trumple 1:27b35752c5d0 128 }
Trumple 1:27b35752c5d0 129
Trumple 1:27b35752c5d0 130 return message;
Trumple 1:27b35752c5d0 131 }
Trumple 1:27b35752c5d0 132
Trumple 1:27b35752c5d0 133 string http::parse(string httpReply)
Trumple 1:27b35752c5d0 134 {
Trumple 2:1cbb20dd1733 135 int payloadBegin = httpReply.find("\r\n\r\n");
Trumple 2:1cbb20dd1733 136
Trumple 2:1cbb20dd1733 137 if (payloadBegin > -1)
Trumple 2:1cbb20dd1733 138 {
Trumple 2:1cbb20dd1733 139 string payload(httpReply.begin() + payloadBegin + 4, httpReply.end());
Trumple 2:1cbb20dd1733 140
Trumple 2:1cbb20dd1733 141 return payload;
Trumple 2:1cbb20dd1733 142 }
Trumple 2:1cbb20dd1733 143 else
Trumple 2:1cbb20dd1733 144 {
Trumple 2:1cbb20dd1733 145 return "";
Trumple 2:1cbb20dd1733 146 }
Trumple 1:27b35752c5d0 147 }