forked from csquared/arduino-restclient
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRestClient.cpp
More file actions
187 lines (167 loc) · 5.17 KB
/
RestClient.cpp
File metadata and controls
187 lines (167 loc) · 5.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#include "RestClient.h"
#include <avr/wdt.h>
RestClient::RestClient(SIM900Client *client, char *buffer, size_t bufferSize){
_client = client;
_contentTypeSet = false;
_buffer = buffer;
_bufferSize = bufferSize;
}
#ifdef DEBUG
char *RestClient::setDebugSerial(Stream* debug){
_debug = debug;
_debug->println(F("RestClient debugging activated!"));
}
#endif
char *RestClient::initialize(HttpMethod_t method, char* path) {
// Make a HTTP request line:
switch(method) {
case GET:
strcpy_P(_buffer,PSTR("GET"));
break;
case POST:
strcpy_P(_buffer,PSTR("POST"));
break;
case PUT:
strcpy_P(_buffer,PSTR("PUT"));
break;
case DELETE:
strcpy_P(_buffer,PSTR("DELETE"));
break;
}
strcat_P(_buffer, PSTR(" "));
strcat(_buffer, path);
strcat_P(_buffer, PSTR(" HTTP/1.1"));
_written = strlen(_buffer);
_buffer[_written++] = '\r';
_buffer[_written++] = '\n';
_buffer[_written++] = '\0';
return _buffer;
}
char *RestClient::addHeader(const char* header){
if(_written + strlen_P(header) + 3 > _bufferSize) return NULL; // we cannot overwrite the buffer
strcat_P(_buffer, header);
if(!_contentTypeSet && strstr_P(_buffer, PSTR("Content-Type"))!=0) {
// we just wrote the Content-Type header
_contentTypeSet = true;
}
_written = strlen(_buffer);
_buffer[_written++] = '\r';
_buffer[_written++] = '\n';
_buffer[_written++] = '\0';
return &_buffer[_written - strlen_P(header) - 2]; // return pointer to start of header if parts are needed to be changed, e.g. write time and date into Date:
}
char *RestClient::getHeaders() {
return _buffer;
}
void RestClient::execute(const char *host, const char* body, size_t bodySize, bool keepAlive){
_client->print(_buffer);
_client->print(F("Host: "));
_client->println(host);
if(keepAlive) {
_client->println(F("Connection: Keep-Alive"));
} else {
_client->println(F("Connection: close"));
}
if(body != NULL){
_client->print(F("Content-Length: "));
_client->println(bodySize);
if(!_contentTypeSet){
_client->println(F("Content-Type: application/x-www-form-urlencoded"));
}
}
_client->println();
if(body != NULL){
_client->print(body);
}
//make sure we write all those bytes.
delay(100);
}
int RestClient::readResponse(char* response, size_t responseSize, char* headerPtrs[], size_t headerSizes[], uint8_t headers) {
long _startTime = millis();
int responseCode = 0;
byte n = 0;
bool httpBody = false;
bool chunkedBody = false; // handles chunked bodies partially, will only read first chunk and return it
long chunkSize = 0;
if(response == NULL){ // we need a response buffer to read anything so cannot only parse the response code
return 0;
}
while (true) { // keep reading lines until we found bodys first line or timeout
wdt_reset();
if (_client->available() == 0) {
delay(10); // wait shortly until we get something to read
} else {
int read = _client->readln((uint8_t *)response, responseSize);
#ifdef DEBUG
_debug->print(F("RestClient read "));
_debug->print(read);
_debug->println(F(" bytes of data."));
#endif
if(httpBody) {
if(chunkedBody && chunkSize == 0) {
chunkSize = strtol(response, NULL, 16); // currently only use the chunksize to determined that we have read it
} else {
#ifdef DEBUG
_debug->println(F("RestClient has read body."));
#endif
// we have just read the http body, break out to return since that is what we are looking for
break;
}
}
if(response[0]== '\0') { // an empty line indicates start of body
#ifdef DEBUG
_debug->println(F("RestClient start of body."));
#endif
httpBody = true;
}
if (0 == n++) {
// first line, parse response code, RFC 2616, section 6.1
// HTTP-Version SP Status-Code SP Reason-Phrase CRLF
// HTTP/1.x
char *statusStart = strchr(response, ' ')+1; // response points at start of Status-Code
char *statusEnd = strchr(statusStart, ' ');
statusEnd = '\0'; // end the string
responseCode = atoi(statusStart);
#ifdef DEBUG
_debug->print(F("RestClient response code "));
_debug->print(responseCode);
_debug->println(F("."));
#endif
} else {
if(strncmp_P(response, PSTR("Transfer-Encoding:"), 18) == 0) {
chunkedBody = strncmp_P(&response[19], PSTR("chunked"), 7) == 0;
#ifdef DEBUG
_debug->print(F("RestClient chunked body '"));
_debug->print(response);
_debug->println(F("'."));
#endif
} else if(headers !=0) {
int i;
for(i=0;i<headers;i++) {
if(headerPtrs[i] != NULL && strncmp(response, headerPtrs[i], strlen(headerPtrs[i])) == 0) {
#ifdef DEBUG
_debug->print(F("RestClient read header "));
_debug->println(headerPtrs[i]);
#endif
// found the header, copy the whole header to the header str
strlcpy(headerPtrs[i], response, headerSizes[i]);
}
}
}
}
if(255 == n) { // we cannot handle more than 255 lines, break!
#ifdef DEBUG
_debug->println(F("RestClient too many lines."));
#endif
break;
}
}
if( (millis() - _startTime) > 20000) { // heroku for instance can take up to 16 seconds to restart a dyno
#ifdef DEBUG
_debug->println(F("RestClient timeout on response."));
#endif
break; ; // timed out
}
}
return responseCode;
}