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