friendev EtherDune TCP/IP library
/home/jander/temp/etherdune/HTTPServer.cpp
Go to the documentation of this file.
1 // EtherDune HTTP Server class
2 // Author: Javier Peletier <jm@friendev.com>
3 // Summary: Provides an easy way to build a web server
4 //
5 // Copyright (c) 2015 All Rights Reserved, http://friendev.com
6 //
7 // This source is subject to the GPLv2 license.
8 // Please see the License.txt file for more information.
9 // All other rights reserved.
10 //
11 // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
12 // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
13 // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
14 // PARTICULAR PURPOSE.
15 
16 #include "HTTPServer.h"
17 
18 #define AC_LOGLEVEL 6
19 #include <ACLog.h>
20 ACROSS_MODULE("HTTPServer");
21 
22 #define requestPatternStringMaxLength(queryStringLength) "%" QUOTE(queryStringLength) "[^ ] HTTP/%*d.%*d\r\n"
23 #define headerPatternStringMaxLength(headerLength, valueLength) "%" QUOTE(headerLength) "[^:]:% %" QUOTE(valueLength) "[^\r]\r\n"
24 
27 
28 
34 void HTTPServer::onBodyReceived(uint16_t len, const byte* data){}
43 void HTTPServer::onHeaderReceived(const char* headerName, const char* headerValue){}
55 void HTTPServer::onRequest(char* queryString){}
60 
62 {
63 
64 }
65 
70 void HTTPServer::listen(uint16_t port)
71 {
72  localPort = port;
74 }
75 
76 void HTTPServer::onReceive(uint16_t len, const byte* data)
77 {
78  if (stage >= HTTP_SERVER_STAGE_RESPONSE)
79  return;
80 
81  if (crlfcount == 4)
82  {
83  onBodyReceived(len, data);
84 
85  if (stage >= HTTP_SERVER_STAGE_RESPONSE)
86  return;
87 
88  contentLength -= len;
89  if (contentLength == 0)
90  {
91  onRequestEnd();
92  }
93  return;
94  }
95 
96  while (len--)
97  {
98  uint8_t c = *data++;
99 
100  if (requestPattern.signaled)
101  {
102  if (c == '\r' || c == '\n')
103  {
104  crlfcount++;
105  if (crlfcount == 4)
106  {
107  stage = HTTP_SERVER_STAGE_BODY;
108 
109  onBodyBegin();
110 
111  if (stage >= HTTP_SERVER_STAGE_RESPONSE)
112  return;
113 
114  onBodyReceived(len, data);
115 
116  if (stage >= HTTP_SERVER_STAGE_RESPONSE)
117  return;
118 
119  contentLength -= len;
120  if (contentLength == 0)
121  onRequestEnd();
122 
123  return;
124  }
125  }
126  else
127  crlfcount = 0;
128 
129  if (scanner.scan(c, headerName, headerValue))
130  {
131  if (strcasecmp_P(headerName, HTTP_HEADER_CONTENT_LENGTH))
132  {
133  contentLength = atoi(headerValue);
134  }
135  onHeaderReceived(headerName, headerValue);
136  scanner.reset();
137 
138  }
139 
140  }
141  else
142  {
143  if (stage == HTTP_SERVER_STAGE_QUERY_STRING)
144  {
145  if (scanner.scan(c, queryString))
146  {
147  onRequest(queryString);
148 
149  if (stage >= HTTP_SERVER_STAGE_RESPONSE)
150  return;
151 
152  crlfcount = 0;
153  scanner.setPattern(headerPattern);
154  stage = HTTP_SERVER_STAGE_HEADERS;
155  }
156  }
157  else
158  {
159  if (c == ' ')
160  {
161  stage = HTTP_SERVER_STAGE_QUERY_STRING;
162  continue;
163  }
164  httpMethod += c + 2;
165  }
166 
167  }
168  }
169 
170 }
171 
172 void HTTPServer::resetParser()
173 {
174  scanner.setPattern(requestPattern);
175  contentLength = 0;
176  crlfcount = 0;
177  stage = HTTP_SERVER_STAGE_INIT;
178  httpMethod = 0;
179 }
180 
181 void HTTPServer::onConnectRequest()
182 {
183  accept(); //accept any connection request
184 }
185 void HTTPServer::onConnect()
186 {
187  ACTRACE("HTTP connection open");
188  resetParser();
189 }
190 
191 void HTTPServer::onClose()
192 {
193  ACTRACE("HTTP connection closed by peer");
194  close();
195 
196 }
197 
203 void HTTPServer::beginResponse(uint16_t statusCode, const String& message)
204 {
205  stage = HTTP_SERVER_STAGE_RESPONSE;
206  String code(statusCode);
207  write(F("HTTP/1.1 % %\r\n"), &code, &message);
208 }
214 void HTTPServer::beginResponse_P(uint16_t statusCode, PGM_P message)
215 {
216  beginResponse(statusCode, (__FlashStringHelper*)message);
217 }
218 
225 void HTTPServer::writeHeader(const String& headerName, const String& headerValue)
226 {
227  write(F("%:%\r\n"), &headerName, &headerValue);
228 }
229 
236 void HTTPServer::writeHeader_P(PGM_P headerName, const String& headerValue)
237 {
238  writeHeader((__FlashStringHelper*)headerName, headerValue);
239 }
240 
246 void HTTPServer::writeContentTypeHeader(const String& contentType)
247 {
249 }
250 
258 {
259  String contentTypeStr((__FlashStringHelper*)contentType);
260  writeContentTypeHeader(contentTypeStr);
261 }
262 
267 {
268  stage = HTTP_SERVER_STAGE_RESPONSE_BODY;
269  write(F("\r\n"));
270 }
271 
276 {
277  if (stage < HTTP_SERVER_STAGE_RESPONSE_BODY)
279 
280  push();
281  close();
282 
283  stage = HTTP_SERVER_STAGE_RESPONSE_END;
284 }
#define HTTP_SERVER_HEADER_NAME_MAX_LENGTH
max buffer to hold a header name, e.g.
Definition: config.h:240
nint16_t localPort
local TCP or UDP port
Definition: Socket.h:54
void writeHeader(const String &headerName, const String &headerValue)
Writes an HTTP header to the ongoing response stream.
Definition: HTTPServer.cpp:225
void beginResponse(uint16_t statusCode, const String &message="")
Sends out the response line, e.g.
Definition: HTTPServer.cpp:203
static const char HTTP_HEADER_CONTENT_LENGTH[]
The length of the request body in octets (8-bit bytes) .
uint8_t httpMethod
Indicates what HTTP method was used in this request.
Definition: HTTPServer.h:104
uint16_t contentLength
captured length of the incoming request, in bytes.
Definition: HTTPServer.h:107
static const char requestPatternString[]
Definition: HTTPServer.cpp:25
virtual void onBodyBegin()
Called when all HTTP headers have been received and the body of the request is about to arrive...
Definition: HTTPServer.cpp:49
uint16_t write(uint16_t len, const byte *data)
In the case of TCP, writes the given data buffer to the socket.
Definition: Socket.cpp:54
void push()
Sets the PSH TCP flag and also sends data in the outgoing buffer immediately.
Definition: TCPSocket.cpp:498
void listen()
Starts listening on the local port indicated by the localPort property.
Definition: TCPSocket.cpp:91
void beginResponse_P(uint16_t statusCode, PGM_P message)
Sends out the response line, e.g.
Definition: HTTPServer.cpp:214
virtual void onHeaderReceived(const char *headerName, const char *headerValue)
Called once for each header in the request, as they arrive.
Definition: HTTPServer.cpp:43
void beginResponseBody()
Indicates to the client that all headers have been written and that the response body follows...
Definition: HTTPServer.cpp:266
void writeContentTypeHeader(const String &contentType)
Convenient function to write the Content-Type header.
Definition: HTTPServer.cpp:246
#define headerPatternStringMaxLength(headerLength, valueLength)
Definition: HTTPServer.cpp:23
void writeContentTypeHeader_P(PGM_P contentType)
Convenient function to write the Content-Type header.
Definition: HTTPServer.cpp:257
virtual void onRequestEnd()
Called after all the body has been received
Definition: HTTPServer.cpp:59
virtual void onBodyReceived(uint16_t len, const byte *data)
Called once for each fragment of the body that is received.
Definition: HTTPServer.cpp:34
void endResponse()
Ends the connection and finalizes the response.
Definition: HTTPServer.cpp:275
static const char HTTP_HEADER_CONTENT_TYPE[]
The MIME type of the body of the request (used with POST and PUT requests) .
virtual void onRequest(char *queryString)
Called immediately after the first line that contains the HTTP method and query string is received ...
Definition: HTTPServer.cpp:55
#define HTTP_SERVER_HEADER_VALUE_MAX_LENGTH
max buffer to hold a header value, e.g.
Definition: config.h:241
#define requestPatternStringMaxLength(queryStringLength)
Definition: HTTPServer.cpp:22
void writeHeader_P(PGM_P headerName, const String &headerValue)
Writes an HTTP header to the ongoing response stream.
Definition: HTTPServer.cpp:236
void close()
Attempts to gracefully close a connection.
Definition: TCPSocket.cpp:194
void accept()
Accepts a connection request that has been received on the port this instance was listening on ...
Definition: TCPSocket.cpp:101
ACROSS_MODULE("HTTPServer")
#define HTTP_SERVER_QUERY_STRING_MAX_LENGTH
max buffer to hold the entire query string, e.g.
Definition: config.h:242
static const char headerPatternString[]
Definition: HTTPServer.cpp:26