ssi.c
Go to the documentation of this file.
1 /**
2  * @file ssi.c
3  * @brief SSI (Server Side Includes)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * Server Side Includes (SSI) is a simple interpreted server-side scripting
30  * language used to generate dynamic content to web pages
31  *
32  * @author Oryx Embedded SARL (www.oryx-embedded.com)
33  * @version 2.4.4
34  **/
35 
36 //Switch to the appropriate trace level
37 #define TRACE_LEVEL HTTP_TRACE_LEVEL
38 
39 //Dependencies
40 #include "core/net.h"
41 #include "http/http_server.h"
42 #include "http/http_server_misc.h"
43 #include "http/mime.h"
44 #include "http/ssi.h"
45 #include "str.h"
46 #include "debug.h"
47 
48 //File system support?
49 #if (HTTP_SERVER_FS_SUPPORT == ENABLED)
50  #include "fs_port.h"
51 #else
52  #include "resource_manager.h"
53 #endif
54 
55 //Check TCP/IP stack configuration
56 #if (HTTP_SERVER_SUPPORT == ENABLED && HTTP_SERVER_SSI_SUPPORT == ENABLED)
57 
58 
59 /**
60  * @brief Execute SSI script
61  * @param[in] connection Structure representing an HTTP connection
62  * @param[in] uri NULL-terminated string containing the file to process
63  * @param[in] level Current level of recursion
64  * @return Error code
65  **/
66 
67 error_t ssiExecuteScript(HttpConnection *connection, const char_t *uri, uint_t level)
68 {
69  error_t error;
70  size_t length;
71 
72 #if (HTTP_SERVER_FS_SUPPORT == ENABLED)
73  bool_t more;
74  size_t n;
75  size_t pos;
76  char_t *buffer;
77  FsFile *file;
78 #else
79  size_t i;
80  size_t j;
81  const char_t *data;
82 #endif
83 
84  //Recursion limit exceeded?
86  return NO_ERROR;
87 
88  //Retrieve the full pathname
89  httpGetAbsolutePath(connection, uri,
90  connection->buffer, HTTP_SERVER_BUFFER_SIZE);
91 
92 #if (HTTP_SERVER_FS_SUPPORT == ENABLED)
93  //Open the file for reading
94  file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ);
95  //Failed to open the file?
96  if(file == NULL)
97  return ERROR_NOT_FOUND;
98 
99  //Allocate a memory buffer
101  //Failed to allocate memory?
102  if(buffer == NULL)
103  {
104  //Close the file
105  fsCloseFile(file);
106  //Report an error
107  return ERROR_OUT_OF_MEMORY;
108  }
109 #else
110  //Get the resource data associated with the URI
111  error = resGetData(connection->buffer, (const uint8_t **) &data, &length);
112  //The specified URI cannot be found?
113  if(error)
114  return error;
115 #endif
116 
117  //Send the HTTP response header before executing the script
118  if(!level)
119  {
120  //Format HTTP response header
121  connection->response.statusCode = 200;
122  connection->response.contentType = mimeGetType(uri);
123  connection->response.chunkedEncoding = TRUE;
124 
125  //Send the header to the client
126  error = httpWriteHeader(connection);
127  //Any error to report?
128  if(error)
129  {
130 #if (HTTP_SERVER_FS_SUPPORT == ENABLED)
131  //Close the file
132  fsCloseFile(file);
133  //Release memory buffer
134  osFreeMem(buffer);
135 #endif
136  //Return status code
137  return error;
138  }
139  }
140 
141 #if (HTTP_SERVER_FS_SUPPORT == ENABLED)
142  //Point to the beginning of the buffer
143  pos = 0;
144  length = 0;
145 
146  //This flag indicates whether data should be read
147  more = TRUE;
148 
149  //Parse the specified file
150  while(1)
151  {
152  //Read more data if needed
153  if(more)
154  {
155  //Check whether the current position is aligned on 32-bit boundaries
156  n = 4 - ((pos + length) % 4);
157 
158  //Maintain proper alignment
159  if(n != 4)
160  {
161  osMemmove(buffer + pos + n, buffer + pos, length);
162  pos += n;
163  }
164 
165  //Read data from the specified file
166  error = fsReadFile(file, buffer + pos + length,
167  HTTP_SERVER_BUFFER_SIZE - (pos + length), &n);
168 
169  //End of input stream?
170  if(error)
171  {
172  //Purge data buffer
173  error = httpWriteStream(connection, buffer + pos, length);
174  //Exit immediately
175  break;
176  }
177 
178  //Adjust the length of the buffer
179  length += n;
180  //Clear flag
181  more = FALSE;
182  }
183 
184  //Search for any SSI tags
185  error = ssiSearchTag(buffer + pos, length, "<!--#", 5, &n);
186 
187  //Full match?
188  if(error == NO_ERROR)
189  {
190  //Send the part of the file that precedes the tag
191  error = httpWriteStream(connection, buffer + pos, n);
192  //Failed to send data?
193  if(error)
194  break;
195 
196  //Advance data pointer
197  pos += n;
198  length -= n;
199 
200  //Search for the comment terminator
201  error = ssiSearchTag(buffer + pos + 5, length - 5, "-->", 3, &n);
202 
203  //Full match?
204  if(error == NO_ERROR)
205  {
206  //Advance data pointer over the opening identifier
207  pos += 5;
208  length -= 5;
209 
210  //Process SSI directive
211  error = ssiProcessCommand(connection, buffer + pos, n, uri, level);
212  //Any error to report?
213  if(error)
214  break;
215 
216  //Advance data pointer over the SSI tag
217  pos += n + 3;
218  length -= n + 3;
219  }
220  //No match or partial match?
221  else
222  {
223  if(pos > 0)
224  {
225  //Move the remaining bytes to the start of the buffer
226  osMemmove(buffer, buffer + pos, length);
227  //Rewind to the beginning of the buffer
228  pos = 0;
229  //More data are needed
230  more = TRUE;
231  }
232  else
233  {
234  //Send data to the client
235  error = httpWriteStream(connection, buffer + pos, length);
236  //Any error to report?
237  if(error)
238  break;
239 
240  //Rewind to the beginning of the buffer
241  pos = 0;
242  length = 0;
243  //More data are needed
244  more = TRUE;
245  }
246  }
247  }
248  //Partial match?
249  else if(error == ERROR_PARTIAL_MATCH)
250  {
251  //Send the part of the file that precedes the tag
252  error = httpWriteStream(connection, buffer + pos, n);
253  //Failed to send data?
254  if(error)
255  break;
256 
257  //Advance data pointer
258  pos += n;
259  length -= n;
260 
261  //Move the remaining bytes to the start of the buffer
262  osMemmove(buffer, buffer + pos, length);
263  //Rewind to the beginning of the buffer
264  pos = 0;
265  //More data are needed
266  more = TRUE;
267  }
268  //No match?
269  else
270  {
271  //Send data to the client
272  error = httpWriteStream(connection, buffer + pos, length);
273  //Any error to report?
274  if(error)
275  break;
276 
277  //Rewind to the beginning of the buffer
278  pos = 0;
279  length = 0;
280  //More data are needed
281  more = TRUE;
282  }
283  }
284 
285  //Close the file
286  fsCloseFile(file);
287  //Release memory buffer
288  osFreeMem(buffer);
289 
290  //Properly close the output stream
291  if(!level && error == NO_ERROR)
292  error = httpCloseStream(connection);
293 #else
294  //Parse the specified file
295  while(length > 0)
296  {
297  //Search for any SSI tags
298  error = ssiSearchTag(data, length, "<!--#", 5, &i);
299 
300  //Opening identifier found?
301  if(!error)
302  {
303  //Search for the comment terminator
304  error = ssiSearchTag(data + i + 5, length - i - 5, "-->", 3, &j);
305  }
306 
307  //Check whether a valid SSI tag has been found?
308  if(!error)
309  {
310  //Send the part of the file that precedes the tag
311  error = httpWriteStream(connection, data, i);
312  //Failed to send data?
313  if(error)
314  return error;
315 
316  //Advance data pointer over the opening identifier
317  data += i + 5;
318  length -= i + 5;
319 
320  //Process SSI directive
321  error = ssiProcessCommand(connection, data, j, uri, level);
322  //Any error to report?
323  if(error)
324  return error;
325 
326  //Advance data pointer over the SSI tag
327  data += j + 3;
328  length -= j + 3;
329  }
330  else
331  {
332  //Send the rest of the file
333  error = httpWriteStream(connection, data, length);
334  //Failed to send data?
335  if(error)
336  return error;
337 
338  //Advance data pointer
339  data += length;
340  length = 0;
341  }
342  }
343 
344  //Properly close the output stream
345  if(!level)
346  error = httpCloseStream(connection);
347 #endif
348 
349  //Return status code
350  return error;
351 }
352 
353 
354 /**
355  * @brief Process SSI directive
356  * @param[in] connection Structure representing an HTTP connection
357  * @param[in] tag Pointer to the SSI tag
358  * @param[in] length Total length of the SSI tag
359  * @param[in] uri NULL-terminated string containing the file being processed
360  * @param[in] level Current level of recursion
361  * @return Error code
362  **/
363 
365  const char_t *tag, size_t length, const char_t *uri, uint_t level)
366 {
367  error_t error;
368 
369  //Include command found?
370  if(length > 7 && osStrncasecmp(tag, "include", 7) == 0)
371  {
372  //Process SSI include directive
373  error = ssiProcessIncludeCommand(connection, tag, length, uri, level);
374  }
375  //Echo command found?
376  else if(length > 4 && osStrncasecmp(tag, "echo", 4) == 0)
377  {
378  //Process SSI echo directive
379  error = ssiProcessEchoCommand(connection, tag, length);
380  }
381  //Exec command found?
382  else if(length > 4 && osStrncasecmp(tag, "exec", 4) == 0)
383  {
384  //Process SSI exec directive
385  error = ssiProcessExecCommand(connection, tag, length);
386  }
387  //Unknown command?
388  else
389  {
390  //The server is unable to decode the SSI tag
391  error = ERROR_INVALID_TAG;
392  }
393 
394  //Invalid SSI directive?
395  if(error == ERROR_INVALID_TAG)
396  {
397  //Report a warning to the user
398  error = httpWriteStream(connection, "Warning: Invalid SSI Tag", 24);
399  }
400 
401  //Return status code
402  return error;
403 }
404 
405 
406 /**
407  * @brief Process SSI include directive
408  *
409  * This include directive allows the content of one document to be included
410  * in another. The file parameter defines the included file as relative to
411  * the document path. The virtual parameter defines the included file as
412  * relative to the document root
413  *
414  * @param[in] connection Structure representing an HTTP connection
415  * @param[in] tag Pointer to the SSI tag
416  * @param[in] length Total length of the SSI tag
417  * @param[in] uri NULL-terminated string containing the file being processed
418  * @param[in] level Current level of recursion
419  * @return Error code
420  **/
421 
423  const char_t *tag, size_t length, const char_t *uri, uint_t level)
424 {
425  error_t error;
426  char_t *separator;
427  char_t *attribute;
428  char_t *value;
429  char_t *path;
430  char_t *p;
431 
432  //Discard invalid SSI directives
433  if(length < 7 || length >= HTTP_SERVER_BUFFER_SIZE)
434  return ERROR_INVALID_TAG;
435 
436  //Skip the SSI include command (7 bytes)
437  osMemcpy(connection->buffer, tag + 7, length - 7);
438  //Ensure the resulting string is NULL-terminated
439  connection->buffer[length - 7] = '\0';
440 
441  //Check whether a separator is present
442  separator = osStrchr(connection->buffer, '=');
443  //Separator not found?
444  if(!separator)
445  return ERROR_INVALID_TAG;
446 
447  //Split the tag
448  *separator = '\0';
449 
450  //Get attribute name and value
451  attribute = strTrimWhitespace(connection->buffer);
452  value = strTrimWhitespace(separator + 1);
453 
454  //Remove leading simple or double quote
455  if(value[0] == '\'' || value[0] == '\"')
456  value++;
457 
458  //Get the length of the attribute value
459  length = osStrlen(value);
460 
461  //Remove trailing simple or double quote
462  if(length > 0)
463  {
464  if(value[length - 1] == '\'' || value[length - 1] == '\"')
465  value[length - 1] = '\0';
466  }
467 
468  //Check the length of the filename
470  return ERROR_INVALID_TAG;
471 
472  //The file parameter defines the included file as relative to the document path
473  if(osStrcasecmp(attribute, "file") == 0)
474  {
475  //Allocate a buffer to hold the path to the file to be included
476  path = osAllocMem(osStrlen(uri) + osStrlen(value) + 1);
477  //Failed to allocate memory?
478  if(path == NULL)
479  return ERROR_OUT_OF_MEMORY;
480 
481  //Copy the path identifying the script file being processed
482  osStrcpy(path, uri);
483  //Search for the last slash character
484  p = strrchr(path, '/');
485 
486  //Remove the filename from the path if applicable
487  if(p)
488  {
489  osStrcpy(p + 1, value);
490  }
491  else
492  {
493  osStrcpy(path, value);
494  }
495  }
496  //The virtual parameter defines the included file as relative to the document root
497  else if(osStrcasecmp(attribute, "virtual") == 0)
498  {
499  //Copy the absolute path
500  path = strDuplicate(value);
501  //Failed to duplicate the string?
502  if(path == NULL)
503  return ERROR_OUT_OF_MEMORY;
504  }
505  //Unknown parameter...
506  else
507  {
508  //Report an error
509  return ERROR_INVALID_TAG;
510  }
511 
512  //Use server-side scripting to dynamically generate HTML code?
513  if(httpCompExtension(value, ".stm") ||
514  httpCompExtension(value, ".shtm") ||
515  httpCompExtension(value, ".shtml"))
516  {
517  //SSI processing (Server Side Includes)
518  error = ssiExecuteScript(connection, path, level + 1);
519  }
520  else
521  {
522 #if (HTTP_SERVER_FS_SUPPORT == ENABLED)
523  FsFile *file;
524 
525  //Retrieve the full pathname
526  httpGetAbsolutePath(connection, path,
527  connection->buffer, HTTP_SERVER_BUFFER_SIZE);
528 
529  //Open the file for reading
530  file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ);
531 
532  //Successful operation?
533  if(file)
534  {
535  //Send the contents of the requested file
536  while(1)
537  {
538  //Read data from the specified file
539  error = fsReadFile(file, connection->buffer, HTTP_SERVER_BUFFER_SIZE, &length);
540  //End of input stream?
541  if(error)
542  break;
543 
544  //Send data to the client
545  error = httpWriteStream(connection, connection->buffer, length);
546  //Any error to report?
547  if(error)
548  break;
549  }
550 
551  //Close the file
552  fsCloseFile(file);
553 
554  //Successful file transfer?
555  if(error == ERROR_END_OF_FILE)
556  error = NO_ERROR;
557  }
558  else
559  {
560  //The specified URI cannot be found
561  error = ERROR_NOT_FOUND;
562  }
563 #else
564  const uint8_t *data;
565 
566  //Retrieve the full pathname
567  httpGetAbsolutePath(connection, path,
568  connection->buffer, HTTP_SERVER_BUFFER_SIZE);
569 
570  //Get the resource data associated with the file
571  error = resGetData(connection->buffer, &data, &length);
572 
573  //Send the contents of the requested file
574  if(!error)
575  error = httpWriteStream(connection, data, length);
576 #endif
577  }
578 
579  //Cannot found the specified resource?
580  if(error == ERROR_NOT_FOUND)
581  error = ERROR_INVALID_TAG;
582 
583  //Release previously allocated memory
584  osFreeMem(path);
585  //return status code
586  return error;
587 }
588 
589 
590 /**
591  * @brief Process SSI echo directive
592  *
593  * This echo directive displays the contents of a specified
594  * HTTP environment variable
595  *
596  * @param[in] connection Structure representing an HTTP connection
597  * @param[in] tag Pointer to the SSI tag
598  * @param[in] length Total length of the SSI tag
599  * @return Error code
600  **/
601 
603  size_t length)
604 {
605  error_t error;
606  char_t *separator;
607  char_t *attribute;
608  char_t *value;
609 
610  //Discard invalid SSI directives
611  if(length < 4 || length >= HTTP_SERVER_BUFFER_SIZE)
612  return ERROR_INVALID_TAG;
613 
614  //Skip the SSI echo command (4 bytes)
615  osMemcpy(connection->buffer, tag + 4, length - 4);
616  //Ensure the resulting string is NULL-terminated
617  connection->buffer[length - 4] = '\0';
618 
619  //Check whether a separator is present
620  separator = osStrchr(connection->buffer, '=');
621  //Separator not found?
622  if(!separator)
623  return ERROR_INVALID_TAG;
624 
625  //Split the tag
626  *separator = '\0';
627 
628  //Get attribute name and value
629  attribute = strTrimWhitespace(connection->buffer);
630  value = strTrimWhitespace(separator + 1);
631 
632  //Remove leading simple or double quote
633  if(value[0] == '\'' || value[0] == '\"')
634  value++;
635 
636  //Get the length of the attribute value
637  length = osStrlen(value);
638 
639  //Remove trailing simple or double quote
640  if(length > 0)
641  {
642  if(value[length - 1] == '\'' || value[length - 1] == '\"')
643  value[length - 1] = '\0';
644  }
645 
646  //Enforce attribute name
647  if(osStrcasecmp(attribute, "var") != 0)
648  return ERROR_INVALID_TAG;
649 
650  //Remote address?
651  if(osStrcasecmp(value, "REMOTE_ADDR") == 0)
652  {
653  //The IP address of the host making this request
654  ipAddrToString(&connection->socket->remoteIpAddr, connection->buffer);
655  }
656  //Remote port?
657  else if(osStrcasecmp(value, "REMOTE_PORT") == 0)
658  {
659  //The port number used by the remote host when making this request
660  osSprintf(connection->buffer, "%" PRIu16, connection->socket->remotePort);
661  }
662  //Server address?
663  else if(osStrcasecmp(value, "SERVER_ADDR") == 0)
664  {
665  //The IP address of the server for this URL
666  ipAddrToString(&connection->socket->localIpAddr, connection->buffer);
667  }
668  //Server port?
669  else if(osStrcasecmp(value, "SERVER_PORT") == 0)
670  {
671  //The port number on this server to which this request was directed
672  osSprintf(connection->buffer, "%" PRIu16, connection->socket->localPort);
673  }
674  //Request method?
675  else if(osStrcasecmp(value, "REQUEST_METHOD") == 0)
676  {
677  //The method used for this HTTP request
678  osStrcpy(connection->buffer, connection->request.method);
679  }
680  //Document root?
681  else if(osStrcasecmp(value, "DOCUMENT_ROOT") == 0)
682  {
683  //The root directory
684  osStrcpy(connection->buffer, connection->settings->rootDirectory);
685  }
686  //Document URI?
687  else if(osStrcasecmp(value, "DOCUMENT_URI") == 0)
688  {
689  //The URI for this request relative to the root directory
690  osStrcpy(connection->buffer, connection->request.uri);
691  }
692  //Document name?
693  else if(osStrcasecmp(value, "DOCUMENT_NAME") == 0)
694  {
695  //The full physical path and filename of the document requested
696  httpGetAbsolutePath(connection, connection->request.uri,
697  connection->buffer, HTTP_SERVER_BUFFER_SIZE);
698  }
699  //Query string?
700  else if(osStrcasecmp(value, "QUERY_STRING") == 0)
701  {
702  //The information following the "?" in the URL for this request
703  osStrcpy(connection->buffer, connection->request.queryString);
704  }
705 #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED || HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
706  //User name?
707  else if(osStrcasecmp(value, "AUTH_USER") == 0)
708  {
709  //The username provided by the user to the server
710  osStrcpy(connection->buffer, connection->request.auth.user);
711  }
712  //Authentication method?
713  else if(osStrcasecmp(value, "AUTH_TYPE") == 0)
714  {
715  //Check the authentication method used in this request
716  if(connection->request.auth.mode == HTTP_AUTH_MODE_BASIC)
717  {
718  osStrcpy(connection->buffer, "Basic");
719  }
720  else if(connection->request.auth.mode == HTTP_AUTH_MODE_DIGEST)
721  {
722  osStrcpy(connection->buffer, "Digest");
723  }
724  else
725  {
726  osStrcpy(connection->buffer, "None");
727  }
728  }
729 #endif
730  //GMT time?
731  else if(osStrcasecmp(value, "DATE_GMT") == 0)
732  {
733  //The current date and time in Greenwich Mean Time
734  connection->buffer[0] = '\0';
735  }
736  //Local time?
737  else if(osStrcasecmp(value, "DATE_LOCAL") == 0)
738  {
739  //The current date and time in the local timezone
740  connection->buffer[0] = '\0';
741  }
742  //Unknown variable?
743  else
744  {
745  //Report an error
746  return ERROR_INVALID_TAG;
747  }
748 
749  //Get the length of the resulting string
750  length = osStrlen(connection->buffer);
751 
752  //Send the contents of the specified environment variable
753  error = httpWriteStream(connection, connection->buffer, length);
754  //Failed to send data?
755  if(error)
756  return error;
757 
758  //Successful processing
759  return NO_ERROR;
760 }
761 
762 
763 /**
764  * @brief Process SSI exec directive
765  *
766  * This exec directive executes a program, script, or shell command on
767  * the server. The cmd parameter specifies a server-side command. The
768  * cgi parameter specifies the path to a CGI script
769  *
770  * @param[in] connection Structure representing an HTTP connection
771  * @param[in] tag Pointer to the SSI tag
772  * @param[in] length Total length of the SSI tag
773  * @return Error code
774  **/
775 
777  size_t length)
778 {
779  char_t *separator;
780  char_t *attribute;
781  char_t *value;
782 
783  //First, check whether CGI is supported by the server
784  if(connection->settings->cgiCallback == NULL)
785  return ERROR_INVALID_TAG;
786 
787  //Discard invalid SSI directives
788  if(length < 4 || length >= HTTP_SERVER_BUFFER_SIZE)
789  return ERROR_INVALID_TAG;
790 
791  //Skip the SSI exec command (4 bytes)
792  osMemcpy(connection->buffer, tag + 4, length - 4);
793  //Ensure the resulting string is NULL-terminated
794  connection->buffer[length - 4] = '\0';
795 
796  //Check whether a separator is present
797  separator = osStrchr(connection->buffer, '=');
798  //Separator not found?
799  if(!separator)
800  return ERROR_INVALID_TAG;
801 
802  //Split the tag
803  *separator = '\0';
804 
805  //Get attribute name and value
806  attribute = strTrimWhitespace(connection->buffer);
807  value = strTrimWhitespace(separator + 1);
808 
809  //Remove leading simple or double quote
810  if(value[0] == '\'' || value[0] == '\"')
811  {
812  value++;
813  }
814 
815  //Get the length of the attribute value
816  length = osStrlen(value);
817 
818  //Remove trailing simple or double quote
819  if(length > 0)
820  {
821  if(value[length - 1] == '\'' || value[length - 1] == '\"')
822  {
823  value[length - 1] = '\0';
824  }
825  }
826 
827  //Enforce attribute name
828  if(osStrcasecmp(attribute, "cgi") != 0 &&
829  osStrcasecmp(attribute, "cmd") != 0 &&
830  osStrcasecmp(attribute, "cmd_argument") != 0)
831  {
832  return ERROR_INVALID_TAG;
833  }
834 
835  //Check the length of the CGI parameter
837  return ERROR_INVALID_TAG;
838 
839  //The scratch buffer may be altered by the user-defined callback.
840  //So the CGI parameter must be copied prior to function invocation
841  osStrcpy(connection->cgiParam, value);
842 
843  //Invoke user-defined callback
844  return connection->settings->cgiCallback(connection, connection->cgiParam);
845 }
846 
847 
848 /**
849  * @brief Search a string for a given tag
850  * @param[in] s String to search
851  * @param[in] sLen Length of the string to search
852  * @param[in] tag String containing the tag to search for
853  * @param[in] tagLen Length of the tag
854  * @param[out] pos The index of the first occurrence of the tag in the string,
855  * @retval NO_ERROR if the specified tag has been found
856  * @retval ERROR_PARTIAL_MATCH if a partial match occurs
857  * @retval ERROR_NO_MATCH if the tag does not appear in the string
858  **/
859 
860 error_t ssiSearchTag(const char_t *s, size_t sLen, const char_t *tag,
861  size_t tagLen, size_t *pos)
862 {
863  size_t i;
864  size_t j;
865 
866  //Parse the input string
867  for(i = 0; i <= sLen; i++)
868  {
869  //Compare current substring with the given tag
870  for(j = 0; (i + j) < sLen && j < tagLen; j++)
871  {
872  if(s[i + j] != tag[j])
873  break;
874  }
875 
876  //Check whether a full match occurred
877  if(j == tagLen)
878  {
879  //Save the position of the first character
880  *pos = i;
881  //The specified tag has been found
882  return NO_ERROR;
883  }
884  //Check whether a partial match occurred
885  else if((i + j) == sLen && j > 0)
886  {
887  //Save the position of the first character
888  *pos = i;
889  //The beginning of the tag matches the end of the string
890  return ERROR_PARTIAL_MATCH;
891  }
892  }
893 
894  //The tag does not appear in the string
895  return ERROR_NO_MATCH;
896 }
897 
898 #endif
#define osStrchr(s, c)
Definition: os_port.h:195
String manipulation helper functions.
int bool_t
Definition: compiler_port.h:53
@ ERROR_NOT_FOUND
Definition: error.h:147
error_t httpWriteHeader(HttpConnection *connection)
Send HTTP response header.
Definition: http_server.c:672
HTTP server (HyperText Transfer Protocol)
uint8_t p
Definition: ndp.h:300
char_t * strTrimWhitespace(char_t *s)
Removes all leading and trailing whitespace from a string.
Definition: str.c:78
@ ERROR_PARTIAL_MATCH
Definition: error.h:309
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:222
char_t * ipAddrToString(const IpAddr *ipAddr, char_t *str)
Convert a binary IP address to a string representation.
Definition: ip.c:805
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ HTTP_AUTH_MODE_BASIC
Definition: http_common.h:74
error_t ssiProcessExecCommand(HttpConnection *connection, const char_t *tag, size_t length)
Process SSI exec directive.
Definition: ssi.c:776
error_t ssiExecuteScript(HttpConnection *connection, const char_t *uri, uint_t level)
Execute SSI script.
Definition: ssi.c:67
#define osStrlen(s)
Definition: os_port.h:165
#define HTTP_SERVER_URI_MAX_LEN
Definition: http_server.h:202
char_t * strDuplicate(const char_t *s)
Duplicate a string.
Definition: str.c:42
error_t ssiProcessIncludeCommand(HttpConnection *connection, const char_t *tag, size_t length, const char_t *uri, uint_t level)
Process SSI include directive.
Definition: ssi.c:422
error_t httpWriteStream(HttpConnection *connection, const void *data, size_t length)
Write data to the client.
Definition: http_server.c:817
error_t fsReadFile(FsFile *file, void *data, size_t size, size_t *length)
Read data from the specified file.
__weak_func void * osAllocMem(size_t size)
Allocate a memory block.
#define FALSE
Definition: os_port.h:46
#define osStrncasecmp(s1, s2, length)
Definition: os_port.h:189
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
error_t
Error codes.
Definition: error.h:43
#define osSprintf(dest,...)
Definition: os_port.h:231
#define HttpConnection
Definition: http_server.h:332
__weak_func void osFreeMem(void *p)
Release a previously allocated memory block.
void fsCloseFile(FsFile *file)
Close a file.
@ ERROR_NO_MATCH
Definition: error.h:308
const char_t * mimeGetType(const char_t *filename)
Get the MIME type from a given extension.
Definition: mime.c:113
HTTP server (miscellaneous functions)
FsFile * fsOpenFile(const char_t *path, uint_t mode)
Open the specified file for reading or writing.
@ ERROR_END_OF_FILE
Definition: error.h:159
#define osStrcasecmp(s1, s2)
Definition: os_port.h:183
error_t ssiProcessCommand(HttpConnection *connection, const char_t *tag, size_t length, const char_t *uri, uint_t level)
Process SSI directive.
Definition: ssi.c:364
#define HTTP_SERVER_SSI_MAX_RECURSION
Definition: http_server.h:237
uint8_t length
Definition: tcp.h:368
error_t resGetData(const char_t *path, const uint8_t **data, size_t *length)
File system abstraction layer.
char char_t
Definition: compiler_port.h:48
error_t ssiSearchTag(const char_t *s, size_t sLen, const char_t *tag, size_t tagLen, size_t *pos)
Search a string for a given tag.
Definition: ssi.c:860
error_t ssiProcessEchoCommand(HttpConnection *connection, const char_t *tag, size_t length)
Process SSI echo directive.
Definition: ssi.c:602
uint8_t n
@ HTTP_AUTH_MODE_DIGEST
Definition: http_common.h:75
void httpGetAbsolutePath(HttpConnection *connection, const char_t *relative, char_t *absolute, size_t maxLen)
Retrieve the full pathname to the specified resource.
uint8_t file[128]
Definition: dhcp_common.h:223
uint8_t value[]
Definition: tcp.h:369
bool_t httpCompExtension(const char_t *filename, const char_t *extension)
Compare filename extension.
error_t httpCloseStream(HttpConnection *connection)
Close output stream.
Definition: http_server.c:882
uint8_t s
Definition: igmp_common.h:234
#define HTTP_SERVER_BUFFER_SIZE
Definition: http_server.h:174
@ ERROR_INVALID_TAG
Definition: error.h:114
@ FS_FILE_MODE_READ
Definition: fs_port.h:72
MIME (Multipurpose Internet Mail Extensions)
Embedded resource management.
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
#define osStrcpy(s1, s2)
Definition: os_port.h:207
SSI (Server Side Includes)
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:147
#define HTTP_SERVER_CGI_PARAM_MAX_LEN
Definition: http_server.h:230
void FsFile
File descriptor.
Definition: fs_port_fatfs.h:60