1 /**
2 * @file
3 * HTTPD simple SSI example
4 *
5 * This file demonstrates how to add support for SSI.
6 * It does this in a very simple way by providing the three tags 'HelloWorld'
7 * 'counter', and 'MultiPart'.
8 *
9 * This file also demonstrates how to integrate CGI with SSI.
10 */
11
12 /*
13 * Copyright (c) 2017 Simon Goldschmidt
14 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without modification,
17 * are permitted provided that the following conditions are met:
18 *
19 * 1. Redistributions of source code must retain the above copyright notice,
20 * this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright notice,
22 * this list of conditions and the following disclaimer in the documentation
23 * and/or other materials provided with the distribution.
24 * 3. The name of the author may not be used to endorse or promote products
25 * derived from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
28 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
29 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
30 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
32 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
35 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
36 * OF SUCH DAMAGE.
37 *
38 * This file is part of the lwIP TCP/IP stack.
39 *
40 * Author: Simon Goldschmidt <goldsimon@gmx.de>
41 *
42 */
43
44 #include "lwip/opt.h"
45 #include "ssi_example.h"
46
47 #include "lwip/apps/httpd.h"
48
49 #include "lwip/def.h"
50 #include "lwip/mem.h"
51
52 #include <stdio.h>
53 #include <string.h>
54
55 /** define LWIP_HTTPD_EXAMPLE_SSI_SIMPLE to 1 to enable this ssi example*/
56 #ifndef LWIP_HTTPD_EXAMPLE_SSI_SIMPLE
57 #define LWIP_HTTPD_EXAMPLE_SSI_SIMPLE 0
58 #endif
59
60 /** define LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION to 1 to show how to
61 * integrate CGI into SSI (LWIP_HTTPD_CGI_SSI) */
62 #ifndef LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION
63 #define LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION 0
64 #endif
65
66 #if LWIP_HTTPD_EXAMPLE_SSI_SIMPLE
67
68 #if LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION
69 #if !LWIP_HTTPD_FILE_STATE
70 #error LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION needs LWIP_HTTPD_FILE_STATE
71 #endif
72 #if !LWIP_HTTPD_CGI_SSI
73 #error LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION needs LWIP_HTTPD_CGI_SSI
74 #endif
75
76 #define MAX_CGI_LEN 16
77 #endif
78
79 const char * ssi_example_tags[] = {
80 "HellWorl",
81 "counter",
82 "MultPart"
83 #if LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION
84 ,"CgiParam"
85 #endif
86 };
87
ssi_example_ssi_handler(const char * ssi_tag_name,char * pcInsert,int iInsertLen,u16_t current_tag_part,u16_t * next_tag_part,void * connection_state)88 u16_t ssi_example_ssi_handler(
89 #if LWIP_HTTPD_SSI_RAW
90 const char* ssi_tag_name,
91 #else /* LWIP_HTTPD_SSI_RAW */
92 int iIndex,
93 #endif /* LWIP_HTTPD_SSI_RAW */
94 char *pcInsert, int iInsertLen
95 #if LWIP_HTTPD_SSI_MULTIPART
96 , u16_t current_tag_part, u16_t *next_tag_part
97 #endif /* LWIP_HTTPD_SSI_MULTIPART */
98 #if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE
99 , void *connection_state
100 #endif /* LWIP_HTTPD_FILE_STATE */
101 )
102 {
103 size_t printed;
104 #if LWIP_HTTPD_SSI_RAW
105 /* a real application could use if(!strcmp) blocks here, but we want to keep
106 the differences between configurations small, so translate string to index here */
107 int iIndex;
108 for (iIndex = 0; iIndex < LWIP_ARRAYSIZE(ssi_example_tags); iIndex++) {
109 if(!strcmp(ssi_tag_name, ssi_example_tags[iIndex])) {
110 break;
111 }
112 }
113 #endif
114 #if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE
115 LWIP_UNUSED_ARG(connection_state);
116 #endif
117
118 switch (iIndex) {
119 case 0: /* "HelloWorld" */
120 printed = snprintf(pcInsert, iInsertLen, "Hello World!");
121 break;
122 case 1: /* "counter" */
123 {
124 static int counter;
125 counter++;
126 printed = snprintf(pcInsert, iInsertLen, "%d", counter);
127 }
128 break;
129 case 2: /* "MultPart" */
130 #if LWIP_HTTPD_SSI_MULTIPART
131 switch (current_tag_part) {
132 case 0:
133 printed = snprintf(pcInsert, iInsertLen, "part0");
134 *next_tag_part = 1;
135 break;
136 case 1:
137 printed = snprintf(pcInsert, iInsertLen, "part1");
138 *next_tag_part = 2;
139 break;
140 case 2:
141 printed = snprintf(pcInsert, iInsertLen, "part2");
142 break;
143 default:
144 printed = snprintf(pcInsert, iInsertLen, "unhandled part: %d", (int)current_tag_part);
145 break;
146 }
147 #else
148 printed = snprintf(pcInsert, iInsertLen, "LWIP_HTTPD_SSI_MULTIPART disabled");
149 #endif
150 break;
151 #if LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION
152 case 3:
153 if (connection_state) {
154 char *params = (char *)connection_state;
155 if (*params) {
156 printed = snprintf(pcInsert, iInsertLen, "%s", (char *)params);
157 } else {
158 printed = snprintf(pcInsert, iInsertLen, "none");
159 }
160 } else {
161 printed = snprintf(pcInsert, iInsertLen, "NULL");
162 }
163 break;
164 #endif
165 default: /* unknown tag */
166 printed = 0;
167 break;
168 }
169 LWIP_ASSERT("sane length", printed <= 0xFFFF);
170 return (u16_t)printed;
171 }
172
173 void
ssi_ex_init(void)174 ssi_ex_init(void)
175 {
176 int i;
177 for (i = 0; i < LWIP_ARRAYSIZE(ssi_example_tags); i++) {
178 LWIP_ASSERT("tag too long for LWIP_HTTPD_MAX_TAG_NAME_LEN",
179 strlen(ssi_example_tags[i]) <= LWIP_HTTPD_MAX_TAG_NAME_LEN);
180 }
181
182 http_set_ssi_handler(ssi_example_ssi_handler,
183 #if LWIP_HTTPD_SSI_RAW
184 NULL, 0
185 #else
186 ssi_example_tags, LWIP_ARRAYSIZE(ssi_example_tags)
187 #endif
188 );
189 }
190
191 #if LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION
192 void *
fs_state_init(struct fs_file * file,const char * name)193 fs_state_init(struct fs_file *file, const char *name)
194 {
195 char *ret;
196 LWIP_UNUSED_ARG(file);
197 LWIP_UNUSED_ARG(name);
198 ret = (char *)mem_malloc(MAX_CGI_LEN);
199 if (ret) {
200 *ret = 0;
201 }
202 return ret;
203 }
204
205 void
fs_state_free(struct fs_file * file,void * state)206 fs_state_free(struct fs_file *file, void *state)
207 {
208 LWIP_UNUSED_ARG(file);
209 if (state != NULL) {
210 mem_free(state);
211 }
212 }
213
214 void
httpd_cgi_handler(struct fs_file * file,const char * uri,int iNumParams,char ** pcParam,char ** pcValue,void * connection_state)215 httpd_cgi_handler(struct fs_file *file, const char* uri, int iNumParams,
216 char **pcParam, char **pcValue
217 #if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE
218 , void *connection_state
219 #endif /* LWIP_HTTPD_FILE_STATE */
220 )
221 {
222 LWIP_UNUSED_ARG(file);
223 LWIP_UNUSED_ARG(uri);
224 if (connection_state != NULL) {
225 char *start = (char *)connection_state;
226 char *end = start + MAX_CGI_LEN;
227 int i;
228 memset(start, 0, MAX_CGI_LEN);
229 /* print a string of the arguments: */
230 for (i = 0; i < iNumParams; i++) {
231 size_t len;
232 len = end - start;
233 if (len) {
234 size_t inlen = strlen(pcParam[i]);
235 size_t copylen = LWIP_MIN(inlen, len);
236 memcpy(start, pcParam[i], copylen);
237 start += copylen;
238 len -= copylen;
239 }
240 if (len) {
241 *start = '=';
242 start++;
243 len--;
244 }
245 if (len) {
246 size_t inlen = strlen(pcValue[i]);
247 size_t copylen = LWIP_MIN(inlen, len);
248 memcpy(start, pcValue[i], copylen);
249 start += copylen;
250 len -= copylen;
251 }
252 if (len) {
253 *start = ';';
254 len--;
255 }
256 /* ensure NULL termination */
257 end--;
258 *end = 0;
259 }
260 }
261 }
262 #endif /* LWIP_HTTPD_EXAMPLE_SSI_SIMPLE_CGI_INTEGRATION */
263
264 #endif /* LWIP_HTTPD_EXAMPLE_SSI_SIMPLE */
265