Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
ssi.c
00001 /** 00002 * @file ssi.c 00003 * @brief SSI (Server Side Includes) 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @section Description 00026 * 00027 * Server Side Includes (SSI) is a simple interpreted server-side scripting 00028 * language used to generate dynamic content to web pages 00029 * 00030 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00031 * @version 1.7.6 00032 **/ 00033 00034 //Switch to the appropriate trace level 00035 #define TRACE_LEVEL HTTP_TRACE_LEVEL 00036 00037 //Dependencies 00038 #include "core/net.h" 00039 #include "http/http_server.h" 00040 #include "http/http_server_misc.h" 00041 #include "http/mime.h" 00042 #include "http/ssi.h" 00043 #include "str.h" 00044 #include "debug.h" 00045 00046 //File system support? 00047 #if (HTTP_SERVER_FS_SUPPORT == ENABLED) 00048 #include "fs_port.h" 00049 #else 00050 #include "resource_manager.h" 00051 #endif 00052 00053 //Check TCP/IP stack configuration 00054 #if (HTTP_SERVER_SUPPORT == ENABLED && HTTP_SERVER_SSI_SUPPORT == ENABLED) 00055 00056 00057 /** 00058 * @brief Execute SSI script 00059 * @param[in] connection Structure representing an HTTP connection 00060 * @param[in] uri NULL-terminated string containing the file to process 00061 * @param[in] level Current level of recursion 00062 * @return Error code 00063 **/ 00064 00065 error_t ssiExecuteScript(HttpConnection *connection, const char_t *uri, uint_t level) 00066 { 00067 error_t error; 00068 size_t length; 00069 00070 #if (HTTP_SERVER_FS_SUPPORT == ENABLED) 00071 bool_t more; 00072 uint_t pos; 00073 uint_t n; 00074 char_t *buffer; 00075 FsFile *file; 00076 #else 00077 uint_t i; 00078 uint_t j; 00079 char_t *data; 00080 #endif 00081 00082 //Recursion limit exceeded? 00083 if(level >= HTTP_SERVER_SSI_MAX_RECURSION) 00084 return NO_ERROR; 00085 00086 //Retrieve the full pathname 00087 httpGetAbsolutePath(connection, uri, 00088 connection->buffer, HTTP_SERVER_BUFFER_SIZE); 00089 00090 #if (HTTP_SERVER_FS_SUPPORT == ENABLED) 00091 //Open the file for reading 00092 file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ); 00093 //Failed to open the file? 00094 if(file == NULL) 00095 return ERROR_NOT_FOUND; 00096 00097 //Allocate a memory buffer 00098 buffer = osAllocMem(HTTP_SERVER_BUFFER_SIZE); 00099 //Failed to allocate memory? 00100 if(buffer == NULL) 00101 { 00102 //Close the file 00103 fsCloseFile(file); 00104 //Report an error 00105 return ERROR_OUT_OF_MEMORY; 00106 } 00107 #else 00108 //Get the resource data associated with the URI 00109 error = resGetData(connection->buffer, (uint8_t **) &data, &length); 00110 //The specified URI cannot be found? 00111 if(error) 00112 return error; 00113 #endif 00114 00115 //Send the HTTP response header before executing the script 00116 if(!level) 00117 { 00118 //Format HTTP response header 00119 connection->response.statusCode = 200; 00120 connection->response.contentType = mimeGetType(uri); 00121 connection->response.chunkedEncoding = TRUE; 00122 00123 //Send the header to the client 00124 error = httpWriteHeader(connection); 00125 //Any error to report? 00126 if(error) 00127 { 00128 #if (HTTP_SERVER_FS_SUPPORT == ENABLED) 00129 //Close the file 00130 fsCloseFile(file); 00131 //Release memory buffer 00132 osFreeMem(buffer); 00133 #endif 00134 //Return status code 00135 return error; 00136 } 00137 } 00138 00139 #if (HTTP_SERVER_FS_SUPPORT == ENABLED) 00140 //Point to the beginning of the buffer 00141 pos = 0; 00142 length = 0; 00143 00144 //This flag indicates whether data should be read 00145 more = TRUE; 00146 00147 //Parse the specified file 00148 while(1) 00149 { 00150 //Read more data if needed 00151 if(more) 00152 { 00153 //Check whether the current position is aligned on 32-bit boundaries 00154 n = 4 - ((pos + length) % 4); 00155 00156 //Maintain proper alignment 00157 if(n != 4) 00158 { 00159 memmove(buffer + pos + n, buffer + pos, length); 00160 pos += n; 00161 } 00162 00163 //Read data from the specified file 00164 error = fsReadFile(file, buffer + pos + length, 00165 HTTP_SERVER_BUFFER_SIZE - (pos + length), &n); 00166 00167 //End of input stream? 00168 if(error) 00169 { 00170 //Purge data buffer 00171 error = httpWriteStream(connection, buffer + pos, length); 00172 //Exit immediately 00173 break; 00174 } 00175 00176 //Adjust the length of the buffer 00177 length += n; 00178 //Clear flag 00179 more = FALSE; 00180 } 00181 00182 //Search for any SSI tags 00183 error = ssiSearchTag(buffer + pos, length, "<!--#", 5, &n); 00184 00185 //Full match? 00186 if(error == NO_ERROR) 00187 { 00188 //Send the part of the file that precedes the tag 00189 error = httpWriteStream(connection, buffer + pos, n); 00190 //Failed to send data? 00191 if(error) 00192 break; 00193 00194 //Advance data pointer 00195 pos += n; 00196 length -= n; 00197 00198 //Search for the comment terminator 00199 error = ssiSearchTag(buffer + pos + 5, length - 5, "-->", 3, &n); 00200 00201 //Full match? 00202 if(error == NO_ERROR) 00203 { 00204 //Advance data pointer over the opening identifier 00205 pos += 5; 00206 length -= 5; 00207 00208 //Process SSI directive 00209 error = ssiProcessCommand(connection, buffer + pos, n, uri, level); 00210 //Any error to report? 00211 if(error) 00212 break; 00213 00214 //Advance data pointer over the SSI tag 00215 pos += n + 3; 00216 length -= n + 3; 00217 } 00218 //No match or partial match? 00219 else 00220 { 00221 if(pos > 0) 00222 { 00223 //Move the remaining bytes to the start of the buffer 00224 memmove(buffer, buffer + pos, length); 00225 //Rewind to the beginning of the buffer 00226 pos = 0; 00227 //More data are needed 00228 more = TRUE; 00229 } 00230 else 00231 { 00232 //Send data to the client 00233 error = httpWriteStream(connection, buffer + pos, length); 00234 //Any error to report? 00235 if(error) 00236 break; 00237 00238 //Rewind to the beginning of the buffer 00239 pos = 0; 00240 length = 0; 00241 //More data are needed 00242 more = TRUE; 00243 } 00244 } 00245 } 00246 //Partial match? 00247 else if(error == ERROR_PARTIAL_MATCH) 00248 { 00249 //Send the part of the file that precedes the tag 00250 error = httpWriteStream(connection, buffer + pos, n); 00251 //Failed to send data? 00252 if(error) 00253 break; 00254 00255 //Advance data pointer 00256 pos += n; 00257 length -= n; 00258 00259 //Move the remaining bytes to the start of the buffer 00260 memmove(buffer, buffer + pos, length); 00261 //Rewind to the beginning of the buffer 00262 pos = 0; 00263 //More data are needed 00264 more = TRUE; 00265 } 00266 //No match? 00267 else 00268 { 00269 //Send data to the client 00270 error = httpWriteStream(connection, buffer + pos, length); 00271 //Any error to report? 00272 if(error) 00273 break; 00274 00275 //Rewind to the beginning of the buffer 00276 pos = 0; 00277 length = 0; 00278 //More data are needed 00279 more = TRUE; 00280 } 00281 } 00282 00283 //Close the file 00284 fsCloseFile(file); 00285 //Release memory buffer 00286 osFreeMem(buffer); 00287 00288 //Properly close the output stream 00289 if(!level && error == NO_ERROR) 00290 error = httpCloseStream(connection); 00291 #else 00292 //Parse the specified file 00293 while(length > 0) 00294 { 00295 //Search for any SSI tags 00296 error = ssiSearchTag(data, length, "<!--#", 5, &i); 00297 00298 //Opening identifier found? 00299 if(!error) 00300 { 00301 //Search for the comment terminator 00302 error = ssiSearchTag(data + i + 5, length - i - 5, "-->", 3, &j); 00303 } 00304 00305 //Check whether a valid SSI tag has been found? 00306 if(!error) 00307 { 00308 //Send the part of the file that precedes the tag 00309 error = httpWriteStream(connection, data, i); 00310 //Failed to send data? 00311 if(error) 00312 return error; 00313 00314 //Advance data pointer over the opening identifier 00315 data += i + 5; 00316 length -= i + 5; 00317 00318 //Process SSI directive 00319 error = ssiProcessCommand(connection, data, j, uri, level); 00320 //Any error to report? 00321 if(error) 00322 return error; 00323 00324 //Advance data pointer over the SSI tag 00325 data += j + 3; 00326 length -= j + 3; 00327 } 00328 else 00329 { 00330 //Send the rest of the file 00331 error = httpWriteStream(connection, data, length); 00332 //Failed to send data? 00333 if(error) 00334 return error; 00335 00336 //Advance data pointer 00337 data += length; 00338 length = 0; 00339 } 00340 } 00341 00342 //Properly close the output stream 00343 if(!level) 00344 error = httpCloseStream(connection); 00345 #endif 00346 00347 //Return status code 00348 return error; 00349 } 00350 00351 00352 /** 00353 * @brief Process SSI directive 00354 * @param[in] connection Structure representing an HTTP connection 00355 * @param[in] tag Pointer to the SSI tag 00356 * @param[in] length Total length of the SSI tag 00357 * @param[in] uri NULL-terminated string containing the file being processed 00358 * @param[in] level Current level of recursion 00359 * @return Error code 00360 **/ 00361 00362 error_t ssiProcessCommand(HttpConnection *connection, 00363 const char_t *tag, size_t length, const char_t *uri, uint_t level) 00364 { 00365 error_t error; 00366 00367 //Include command found? 00368 if(length > 7 && !strncasecmp(tag, "include", 7)) 00369 { 00370 //Process SSI include directive 00371 error = ssiProcessIncludeCommand(connection, tag, length, uri, level); 00372 } 00373 //Echo command found? 00374 else if(length > 4 && !strncasecmp(tag, "echo", 4)) 00375 { 00376 //Process SSI echo directive 00377 error = ssiProcessEchoCommand(connection, tag, length); 00378 } 00379 //Exec command found? 00380 else if(length > 4 && !strncasecmp(tag, "exec", 4)) 00381 { 00382 //Process SSI exec directive 00383 error = ssiProcessExecCommand(connection, tag, length); 00384 } 00385 //Unknown command? 00386 else 00387 { 00388 //The server is unable to decode the SSI tag 00389 error = ERROR_INVALID_TAG; 00390 } 00391 00392 //Invalid SSI directive? 00393 if(error == ERROR_INVALID_TAG) 00394 { 00395 //Report a warning to the user 00396 error = httpWriteStream(connection, "Warning: Invalid SSI Tag", 24); 00397 } 00398 00399 //Return status code 00400 return error; 00401 } 00402 00403 00404 /** 00405 * @brief Process SSI include directive 00406 * 00407 * This include directive allows the content of one document to be included 00408 * in another. The file parameter defines the included file as relative to 00409 * the document path. The virtual parameter defines the included file as 00410 * relative to the document root 00411 * 00412 * @param[in] connection Structure representing an HTTP connection 00413 * @param[in] tag Pointer to the SSI tag 00414 * @param[in] length Total length of the SSI tag 00415 * @param[in] uri NULL-terminated string containing the file being processed 00416 * @param[in] level Current level of recursion 00417 * @return Error code 00418 **/ 00419 00420 error_t ssiProcessIncludeCommand(HttpConnection *connection, 00421 const char_t *tag, size_t length, const char_t *uri, uint_t level) 00422 { 00423 error_t error; 00424 char_t *separator; 00425 char_t *attribute; 00426 char_t *value; 00427 char_t *path; 00428 char_t *p; 00429 00430 //Discard invalid SSI directives 00431 if(length < 7 || length >= HTTP_SERVER_BUFFER_SIZE) 00432 return ERROR_INVALID_TAG; 00433 00434 //Skip the SSI include command (7 bytes) 00435 memcpy(connection->buffer, tag + 7, length - 7); 00436 //Ensure the resulting string is NULL-terminated 00437 connection->buffer[length - 7] = '\0'; 00438 00439 //Check whether a separator is present 00440 separator = strchr(connection->buffer, '='); 00441 //Separator not found? 00442 if(!separator) 00443 return ERROR_INVALID_TAG; 00444 00445 //Split the tag 00446 *separator = '\0'; 00447 00448 //Get attribute name and value 00449 attribute = strTrimWhitespace(connection->buffer); 00450 value = strTrimWhitespace(separator + 1); 00451 00452 //Remove leading simple or double quote 00453 if(value[0] == '\'' || value[0] == '\"') 00454 value++; 00455 00456 //Get the length of the attribute value 00457 length = strlen(value); 00458 00459 //Remove trailing simple or double quote 00460 if(length > 0) 00461 { 00462 if(value[length - 1] == '\'' || value[length - 1] == '\"') 00463 value[length - 1] = '\0'; 00464 } 00465 00466 //Check the length of the filename 00467 if(strlen(value) > HTTP_SERVER_URI_MAX_LEN) 00468 return ERROR_INVALID_TAG; 00469 00470 //The file parameter defines the included file as relative to the document path 00471 if(!strcasecmp(attribute, "file")) 00472 { 00473 //Allocate a buffer to hold the path to the file to be included 00474 path = osAllocMem(strlen(uri) + strlen(value) + 1); 00475 //Failed to allocate memory? 00476 if(path == NULL) 00477 return ERROR_OUT_OF_MEMORY; 00478 00479 //Copy the path identifying the script file being processed 00480 strcpy(path, uri); 00481 //Search for the last slash character 00482 p = strrchr(path, '/'); 00483 00484 //Remove the filename from the path if applicable 00485 if(p) 00486 strcpy(p + 1, value); 00487 else 00488 strcpy(path, value); 00489 } 00490 //The virtual parameter defines the included file as relative to the document root 00491 else if(!strcasecmp(attribute, "virtual")) 00492 { 00493 //Copy the absolute path 00494 path = strDuplicate(value); 00495 //Failed to duplicate the string? 00496 if(path == NULL) 00497 return ERROR_OUT_OF_MEMORY; 00498 } 00499 //Unknown parameter... 00500 else 00501 { 00502 //Report an error 00503 return ERROR_INVALID_TAG; 00504 } 00505 00506 //Use server-side scripting to dynamically generate HTML code? 00507 if(httpCompExtension(value, ".stm") || 00508 httpCompExtension(value, ".shtm") || 00509 httpCompExtension(value, ".shtml")) 00510 { 00511 //SSI processing (Server Side Includes) 00512 error = ssiExecuteScript(connection, path, level + 1); 00513 } 00514 else 00515 { 00516 #if (HTTP_SERVER_FS_SUPPORT == ENABLED) 00517 FsFile *file; 00518 00519 //Retrieve the full pathname 00520 httpGetAbsolutePath(connection, path, 00521 connection->buffer, HTTP_SERVER_BUFFER_SIZE); 00522 00523 //Open the file for reading 00524 file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ); 00525 00526 //Successful operation? 00527 if(file) 00528 { 00529 //Send the contents of the requested file 00530 while(1) 00531 { 00532 //Read data from the specified file 00533 error = fsReadFile(file, connection->buffer, HTTP_SERVER_BUFFER_SIZE, &length); 00534 //End of input stream? 00535 if(error) 00536 break; 00537 00538 //Send data to the client 00539 error = httpWriteStream(connection, connection->buffer, length); 00540 //Any error to report? 00541 if(error) 00542 break; 00543 } 00544 00545 //Close the file 00546 fsCloseFile(file); 00547 00548 //Successful file transfer? 00549 if(error == ERROR_END_OF_FILE) 00550 error = NO_ERROR; 00551 } 00552 else 00553 { 00554 //The specified URI cannot be found 00555 error = ERROR_NOT_FOUND; 00556 } 00557 #else 00558 uint8_t *data; 00559 00560 //Retrieve the full pathname 00561 httpGetAbsolutePath(connection, path, 00562 connection->buffer, HTTP_SERVER_BUFFER_SIZE); 00563 00564 //Get the resource data associated with the file 00565 error = resGetData(connection->buffer, &data, &length); 00566 00567 //Send the contents of the requested file 00568 if(!error) 00569 error = httpWriteStream(connection, data, length); 00570 #endif 00571 } 00572 00573 //Cannot found the specified resource? 00574 if(error == ERROR_NOT_FOUND) 00575 error = ERROR_INVALID_TAG; 00576 00577 //Release previously allocated memory 00578 osFreeMem(path); 00579 //return status code 00580 return error; 00581 } 00582 00583 00584 /** 00585 * @brief Process SSI echo directive 00586 * 00587 * This echo directive displays the contents of a specified 00588 * HTTP environment variable 00589 * 00590 * @param[in] connection Structure representing an HTTP connection 00591 * @param[in] tag Pointer to the SSI tag 00592 * @param[in] length Total length of the SSI tag 00593 * @return Error code 00594 **/ 00595 00596 error_t ssiProcessEchoCommand(HttpConnection *connection, const char_t *tag, size_t length) 00597 { 00598 error_t error; 00599 char_t *separator; 00600 char_t *attribute; 00601 char_t *value; 00602 00603 //Discard invalid SSI directives 00604 if(length < 4 || length >= HTTP_SERVER_BUFFER_SIZE) 00605 return ERROR_INVALID_TAG; 00606 00607 //Skip the SSI echo command (4 bytes) 00608 memcpy(connection->buffer, tag + 4, length - 4); 00609 //Ensure the resulting string is NULL-terminated 00610 connection->buffer[length - 4] = '\0'; 00611 00612 //Check whether a separator is present 00613 separator = strchr(connection->buffer, '='); 00614 //Separator not found? 00615 if(!separator) 00616 return ERROR_INVALID_TAG; 00617 00618 //Split the tag 00619 *separator = '\0'; 00620 00621 //Get attribute name and value 00622 attribute = strTrimWhitespace(connection->buffer); 00623 value = strTrimWhitespace(separator + 1); 00624 00625 //Remove leading simple or double quote 00626 if(value[0] == '\'' || value[0] == '\"') 00627 value++; 00628 00629 //Get the length of the attribute value 00630 length = strlen(value); 00631 00632 //Remove trailing simple or double quote 00633 if(length > 0) 00634 { 00635 if(value[length - 1] == '\'' || value[length - 1] == '\"') 00636 value[length - 1] = '\0'; 00637 } 00638 00639 //Enforce attribute name 00640 if(strcasecmp(attribute, "var")) 00641 return ERROR_INVALID_TAG; 00642 00643 //Remote address? 00644 if(!strcasecmp(value, "REMOTE_ADDR")) 00645 { 00646 //The IP address of the host making this request 00647 ipAddrToString(&connection->socket->remoteIpAddr, connection->buffer); 00648 } 00649 //Remote port? 00650 else if(!strcasecmp(value, "REMOTE_PORT")) 00651 { 00652 //The port number used by the remote host when making this request 00653 sprintf(connection->buffer, "%" PRIu16, connection->socket->remotePort); 00654 } 00655 //Server address? 00656 else if(!strcasecmp(value, "SERVER_ADDR")) 00657 { 00658 //The IP address of the server for this URL 00659 ipAddrToString(&connection->socket->localIpAddr, connection->buffer); 00660 } 00661 //Server port? 00662 else if(!strcasecmp(value, "SERVER_PORT")) 00663 { 00664 //The port number on this server to which this request was directed 00665 sprintf(connection->buffer, "%" PRIu16, connection->socket->localPort); 00666 } 00667 //Request method? 00668 else if(!strcasecmp(value, "REQUEST_METHOD")) 00669 { 00670 //The method used for this HTTP request 00671 strcpy(connection->buffer, connection->request.method); 00672 } 00673 //Document root? 00674 else if(!strcasecmp(value, "DOCUMENT_ROOT")) 00675 { 00676 //The root directory 00677 strcpy(connection->buffer, connection->settings->rootDirectory); 00678 } 00679 //Document URI? 00680 else if(!strcasecmp(value, "DOCUMENT_URI")) 00681 { 00682 //The URI for this request relative to the root directory 00683 strcpy(connection->buffer, connection->request.uri); 00684 } 00685 //Document name? 00686 else if(!strcasecmp(value, "DOCUMENT_NAME")) 00687 { 00688 //The full physical path and filename of the document requested 00689 httpGetAbsolutePath(connection, connection->request.uri, 00690 connection->buffer, HTTP_SERVER_BUFFER_SIZE); 00691 } 00692 //Query string? 00693 else if(!strcasecmp(value, "QUERY_STRING")) 00694 { 00695 //The information following the "?" in the URL for this request 00696 strcpy(connection->buffer, connection->request.queryString); 00697 } 00698 //User name? 00699 else if(!strcasecmp(value, "AUTH_USER")) 00700 { 00701 #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED || HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED) 00702 //The username provided by the user to the server 00703 strcpy(connection->buffer, connection->request.auth.user); 00704 #else 00705 //Basic access authentication is not supported 00706 connection->buffer[0] = '\0'; 00707 #endif 00708 } 00709 //GMT time? 00710 else if(!strcasecmp(value, "DATE_GMT")) 00711 { 00712 //The current date and time in Greenwich Mean Time 00713 connection->buffer[0] = '\0'; 00714 } 00715 //Local time? 00716 else if(!strcasecmp(value, "DATE_LOCAL")) 00717 { 00718 //The current date and time in the local timezone 00719 connection->buffer[0] = '\0'; 00720 } 00721 //Unknown variable? 00722 else 00723 { 00724 //Report an error 00725 return ERROR_INVALID_TAG; 00726 } 00727 00728 //Get the length of the resulting string 00729 length = strlen(connection->buffer); 00730 00731 //Send the contents of the specified environment variable 00732 error = httpWriteStream(connection, connection->buffer, length); 00733 //Failed to send data? 00734 if(error) 00735 return error; 00736 00737 //Successful processing 00738 return NO_ERROR; 00739 } 00740 00741 00742 /** 00743 * @brief Process SSI exec directive 00744 * 00745 * This exec directive executes a program, script, or shell command on 00746 * the server. The cmd parameter specifies a server-side command. The 00747 * cgi parameter specifies the path to a CGI script 00748 * 00749 * @param[in] connection Structure representing an HTTP connection 00750 * @param[in] tag Pointer to the SSI tag 00751 * @param[in] length Total length of the SSI tag 00752 * @return Error code 00753 **/ 00754 00755 error_t ssiProcessExecCommand(HttpConnection *connection, const char_t *tag, size_t length) 00756 { 00757 char_t *separator; 00758 char_t *attribute; 00759 char_t *value; 00760 00761 //First, check whether CGI is supported by the server 00762 if(connection->settings->cgiCallback == NULL) 00763 return ERROR_INVALID_TAG; 00764 00765 //Discard invalid SSI directives 00766 if(length < 4 || length >= HTTP_SERVER_BUFFER_SIZE) 00767 return ERROR_INVALID_TAG; 00768 00769 //Skip the SSI exec command (4 bytes) 00770 memcpy(connection->buffer, tag + 4, length - 4); 00771 //Ensure the resulting string is NULL-terminated 00772 connection->buffer[length - 4] = '\0'; 00773 00774 //Check whether a separator is present 00775 separator = strchr(connection->buffer, '='); 00776 //Separator not found? 00777 if(!separator) 00778 return ERROR_INVALID_TAG; 00779 00780 //Split the tag 00781 *separator = '\0'; 00782 00783 //Get attribute name and value 00784 attribute = strTrimWhitespace(connection->buffer); 00785 value = strTrimWhitespace(separator + 1); 00786 00787 //Remove leading simple or double quote 00788 if(value[0] == '\'' || value[0] == '\"') 00789 value++; 00790 00791 //Get the length of the attribute value 00792 length = strlen(value); 00793 00794 //Remove trailing simple or double quote 00795 if(length > 0) 00796 { 00797 if(value[length - 1] == '\'' || value[length - 1] == '\"') 00798 value[length - 1] = '\0'; 00799 } 00800 00801 //Enforce attribute name 00802 if(strcasecmp(attribute, "cgi") && strcasecmp(attribute, "cmd") && strcasecmp(attribute, "cmd_argument")) 00803 return ERROR_INVALID_TAG; 00804 //Check the length of the CGI parameter 00805 if(strlen(value) > HTTP_SERVER_CGI_PARAM_MAX_LEN) 00806 return ERROR_INVALID_TAG; 00807 00808 //The scratch buffer may be altered by the user-defined callback. 00809 //So the CGI parameter must be copied prior to function invocation 00810 strcpy(connection->cgiParam, value); 00811 00812 //Invoke user-defined callback 00813 return connection->settings->cgiCallback(connection, connection->cgiParam); 00814 } 00815 00816 00817 /** 00818 * @brief Search a string for a given tag 00819 * @param[in] s String to search 00820 * @param[in] sLen Length of the string to search 00821 * @param[in] tag String containing the tag to search for 00822 * @param[in] tagLen Length of the tag 00823 * @param[out] pos The index of the first occurrence of the tag in the string, 00824 * @retval NO_ERROR if the specified tag has been found 00825 * @retval ERROR_PARTIAL_MATCH if a partial match occurs 00826 * @retval ERROR_NO_MATCH if the tag does not appear in the string 00827 **/ 00828 00829 error_t ssiSearchTag(const char_t *s, size_t sLen, const char_t *tag, size_t tagLen, uint_t *pos) 00830 { 00831 uint_t i; 00832 uint_t j; 00833 00834 //Parse the input string 00835 for(i = 0; i <= sLen; i++) 00836 { 00837 //Compare current substring with the given tag 00838 for(j = 0; (i + j) < sLen && j < tagLen; j++) 00839 { 00840 if(s[i + j] != tag[j]) 00841 break; 00842 } 00843 00844 //Check whether a full match occurred 00845 if(j == tagLen) 00846 { 00847 //Save the position of the first character 00848 *pos = i; 00849 //The specified tag has been found 00850 return NO_ERROR; 00851 } 00852 //Check whether a partial match occurred 00853 else if((i + j) == sLen && j > 0) 00854 { 00855 //Save the position of the first character 00856 *pos = i; 00857 //The beginning of the tag matches the end of the string 00858 return ERROR_PARTIAL_MATCH; 00859 } 00860 } 00861 00862 //The tag does not appear in the string 00863 return ERROR_NO_MATCH; 00864 } 00865 00866 #endif 00867
Generated on Tue Jul 12 2022 17:10:16 by
1.7.2