libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

mhd_post_parser.h (16453B)


      1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
      2 /*
      3   This file is part of GNU libmicrohttpd.
      4   Copyright (C) 2024 Evgeny Grin (Karlson2k)
      5 
      6   GNU libmicrohttpd is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU Lesser General Public
      8   License as published by the Free Software Foundation; either
      9   version 2.1 of the License, or (at your option) any later version.
     10 
     11   GNU libmicrohttpd is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   Lesser General Public License for more details.
     15 
     16   Alternatively, you can redistribute GNU libmicrohttpd and/or
     17   modify it under the terms of the GNU General Public License as
     18   published by the Free Software Foundation; either version 2 of
     19   the License, or (at your option) any later version, together
     20   with the eCos exception, as follows:
     21 
     22     As a special exception, if other files instantiate templates or
     23     use macros or inline functions from this file, or you compile this
     24     file and link it with other works to produce a work based on this
     25     file, this file does not by itself cause the resulting work to be
     26     covered by the GNU General Public License. However the source code
     27     for this file must still be made available in accordance with
     28     section (3) of the GNU General Public License v2.
     29 
     30     This exception does not invalidate any other reasons why a work
     31     based on this file might be covered by the GNU General Public
     32     License.
     33 
     34   You should have received copies of the GNU Lesser General Public
     35   License and the GNU General Public License along with this library;
     36   if not, see <https://www.gnu.org/licenses/>.
     37 */
     38 
     39 /**
     40  * @file src/mhd2/mhd_post_parser.h
     41  * @brief  The definition of the post parsers data structures
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 #ifndef MHD_POST_PARSER_H
     46 #define MHD_POST_PARSER_H 1
     47 
     48 #include "mhd_sys_options.h"
     49 
     50 #include "sys_base_types.h"
     51 #include "sys_bool_type.h"
     52 
     53 #include "http_post_enc.h"
     54 #include "mhd_post_result.h"
     55 #include "mhd_buffer.h"
     56 
     57 #ifdef SIZE_MAX
     58 #  define mhd_POST_INVALID_POS SIZE_MAX
     59 #else
     60 #  define mhd_POST_INVALID_POS ((size_t) (~((size_t) (0))))
     61 #endif
     62 
     63 /**
     64  * The states of the "application/x-www-form-urlencoded" field parsing
     65  */
     66 enum MHD_FIXED_ENUM_ mhd_PostUrlEncState
     67 {
     68   /**
     69    * The field processing has not been started
     70    */
     71   mhd_POST_UENC_ST_NOT_STARTED = 0
     72   ,
     73   /**
     74    * Processing name of the field
     75    */
     76   mhd_POST_UENC_ST_NAME
     77   ,
     78   /**
     79    * At the '=' character after the name.
     80    * This is an intermediate state, should be processed and switched to the next
     81    * state immediately.
     82    * Should not be used outside processing loop.
     83    */
     84   mhd_POST_UENC_ST_AT_EQ
     85   ,
     86   /**
     87    * The '=' character after the name has been found.
     88    * Looking for the first value character.
     89    */
     90   mhd_POST_UENC_ST_EQ_FOUND
     91   ,
     92   /**
     93    * Processing the value of the field.
     94    */
     95   mhd_POST_UENC_ST_VALUE
     96   ,
     97   /**
     98    * At the ampersand '&' character.
     99    * Means that full field is found.
    100    * This is an intermediate state, should be processed and switched to the next
    101    * state immediately.
    102    * Should not be used outside processing loop.
    103    */
    104   mhd_POST_UENC_ST_AT_AMPRSND
    105   ,
    106   /**
    107    * Full field found.
    108    * This is an intermediate state, should be processed and switched to the next
    109    * state immediately.
    110    * Should not be used outside processing loop.
    111    */
    112   mhd_POST_UENC_ST_FULL_FIELD_FOUND
    113 };
    114 
    115 /**
    116  * The "application/x-www-form-urlencoded" parsing data
    117  */
    118 struct mhd_PostParserUrlEncData
    119 {
    120   /**
    121    * The parsing state
    122    */
    123   enum mhd_PostUrlEncState st;
    124 
    125   /**
    126    * The index of the start of the name.
    127    */
    128   size_t name_idx;
    129 
    130   /**
    131    * The length of the name of the current field, not including
    132    * the terminating zero.
    133    * Zero until the length is found.
    134    */
    135   size_t name_len;
    136 
    137   /**
    138    * The index of the start of the value.
    139    * Zero until the value is found.
    140    * Cannot be zero if any (including zero-length) value available.
    141    */
    142   size_t value_idx;
    143 
    144   /**
    145    * The length of the value of the current field, not including
    146    * the terminating zero.
    147    * Zero until the length is found.
    148    * If @a st is #mhd_POST_UENC_ST_VALUE and @a value_len is not zero,
    149    * then it is the length of the partial (decoded) value provided previously
    150    * to the "stream" processing callback (which responded with a "suspend"
    151    * action).
    152    */
    153   size_t value_len;
    154 
    155   /**
    156    * The index of the last percent ('%') character found.
    157    * Set to #mhd_POST_INVALID_POS when no '%' char found.
    158    * Used for two proposes:
    159    * + indicates that "name" or "value" needs persent-deconding
    160    * + helps to detect incomplete percent-encoded char for stream processing
    161    */
    162   size_t last_pct_idx;
    163 };
    164 
    165 
    166 /**
    167  * The states of the "multipart/form-data" parsing
    168  */
    169 enum MHD_FIXED_ENUM_ mhd_PostMPartState
    170 {
    171   /**
    172    * The parsing has not been started
    173    * Should not be used outside processing loop except initial initialisation.
    174    */
    175   mhd_POST_MPART_ST_NOT_STARTED = 0
    176   ,
    177   /**
    178    * Check for delimiter failed, continuing processing of the preabmle
    179    * This is an intermediate state, should be processed and switched to the next
    180    * state immediately.
    181    * Should not be used outside processing loop.
    182    */
    183   mhd_POST_MPART_ST_BACK_TO_PREAMBL
    184   ,
    185   /**
    186    * Processing preabmle
    187    */
    188   mhd_POST_MPART_ST_PREAMBL
    189   ,
    190   /**
    191    * Found CR char in the preamble
    192    */
    193   mhd_POST_MPART_ST_PREAMBL_CR_FOUND
    194   ,
    195   /**
    196    * Found LF char in the preamble (after CR or just bare LF if allowed)
    197    * This is an intermediate state, should be processed and switched to the next
    198    * state immediately.
    199    * Should not be used outside processing loop.
    200    */
    201   mhd_POST_MPART_ST_PREAMBL_LINE_START
    202   ,
    203   /**
    204    * Checking for potential delimiter marker at the start of the string
    205    */
    206   mhd_POST_MPART_ST_PREAMBL_CHECKING_FOR_DELIM
    207   ,
    208   /**
    209    * Found the first delimiter.
    210    * Need to find the end of the delimiter string and check for possible "final"
    211    * delimiter.
    212    */
    213   mhd_POST_MPART_ST_FIRST_DELIM_FOUND
    214   ,
    215   /**
    216    * Found start of the first "part"
    217    * This is an intermediate state, should be processed and switched to the next
    218    * state immediately.
    219    */
    220   mhd_POST_MPART_ST_FIRST_PART_START
    221   ,
    222   /**
    223    * Found start of the "part" (after the delimiter)
    224    * This is an intermediate state, should be processed and switched to the next
    225    * state immediately.
    226    */
    227   mhd_POST_MPART_ST_PART_START
    228   ,
    229   /**
    230    * Starting processing of embedded header line
    231    */
    232   mhd_POST_MPART_ST_HEADER_LINE_START
    233   ,
    234   /**
    235    * Processing embedded header line
    236    */
    237   mhd_POST_MPART_ST_HEADER_LINE
    238   ,
    239   /**
    240    * Found CR char in the embedded header line
    241    */
    242   mhd_POST_MPART_ST_HEADER_LINE_CR_FOUND
    243   ,
    244   /**
    245    * Found complete embedded header line, at the final character.
    246    * This is an intermediate state, should be processed and switched to the next
    247    * state immediately.
    248    * Should not be used outside processing loop.
    249    */
    250   mhd_POST_MPART_ST_HEADER_LINE_END
    251   ,
    252   /**
    253    * Starting processing of the "value"
    254    * This is an intermediate state, should be processed and switched to the next
    255    * state immediately.
    256    */
    257   mhd_POST_MPART_ST_VALUE_START
    258   ,
    259   /**
    260    * Check for delimiter failed, continuing processing of the "value"
    261    * This is an intermediate state, should be processed and switched to the next
    262    * state immediately.
    263    * Can be used outside processing loop if streaming partial value.
    264    */
    265   mhd_POST_MPART_ST_BACK_TO_VALUE
    266   ,
    267   /**
    268    * Processing "value"
    269    */
    270   mhd_POST_MPART_ST_VALUE
    271   ,
    272   /**
    273    * Found CR char in the "value"
    274    */
    275   mhd_POST_MPART_ST_VALUE_CR_FOUND
    276   ,
    277   /**
    278    * Found LF char in the "value"
    279    */
    280   mhd_POST_MPART_ST_VALUE_LINE_START
    281   ,
    282   /**
    283    * Checking for potential delimiter marker at the start of the string
    284    */
    285   mhd_POST_MPART_ST_VALUE_CHECKING_FOR_DELIM
    286   ,
    287   /**
    288    * Found the delimiter.
    289    * Need to find the end of the delimiter string and check for possible "final"
    290    * delimiter.
    291    */
    292   mhd_POST_MPART_ST_DELIM_FOUND
    293   ,
    294   /**
    295    * Found the end of the "value"
    296    * This is an intermediate state, should be processed and switched to the next
    297    * state immediately.
    298    * Should not be used outside processing loop.
    299    */
    300   mhd_POST_MPART_ST_VALUE_END_FOUND
    301   ,
    302   /**
    303    * Found the end of the "value" closed by the "final" delimiter
    304    * This is an intermediate state, should be processed and switched to the next
    305    * state immediately.
    306    * Should not be used outside processing loop.
    307    */
    308   mhd_POST_MPART_ST_VALUE_END_FOUND_FINAL
    309   ,
    310   /**
    311    * Found the complete field
    312    */
    313   mhd_POST_MPART_ST_FULL_FIELD_FOUND
    314   ,
    315   /**
    316    * Found the complete field closed by the "final" delimiter
    317    */
    318   mhd_POST_MPART_ST_FULL_FIELD_FOUND_FINAL
    319   ,
    320   /**
    321    * Processing "epilogue"
    322    */
    323   mhd_POST_MPART_ST_EPILOGUE
    324   ,
    325   /**
    326    * The format of the input data is invalid
    327    */
    328   mhd_POST_MPART_ST_FORMAT_ERROR
    329 };
    330 
    331 
    332 /**
    333  * The "multipart/form-data" field parsing data
    334  */
    335 struct mhd_PostParserMPartFieldData
    336 {
    337   /**
    338    * The index of the start of the name.
    339    */
    340   size_t name_idx;
    341   /**
    342    * The length of the name of the current field, not including
    343    * the terminating zero.
    344    * Zero until the length is found.
    345    */
    346   size_t name_len;
    347   /**
    348    * The index of the start of the value.
    349    * Zero until the value is found.
    350    * Cannot be zero if any (including zero-length) value available.
    351    */
    352   size_t value_idx;
    353   /**
    354    * The length of the value of the current field, not including
    355    * the terminating zero.
    356    * Zero until the length is found.
    357    */
    358   size_t value_len;
    359   /**
    360    * The index of the start of the filename of the current field.
    361    * Zero until the value is found.
    362    * Cannot be zero if any (including zero-length) filename available.
    363    */
    364   size_t filename_idx;
    365   /**
    366    * The length of the filename of the current field, not including
    367    * the terminating zero.
    368    * Zero until the length is found.
    369    */
    370   size_t filename_len;
    371   /**
    372    * The index of the start of the value of the Content-Type of the current
    373    * field.
    374    * Zero until the value is found.
    375    * Cannot be zero if any (including zero-length) filename available.
    376    */
    377   size_t cntn_type_idx;
    378   /**
    379    * The length of the filename of the value of the Content-Type of the current
    380    * field, not including the terminating zero.
    381    * Zero until the length is found.
    382    */
    383   size_t cntn_type_len;
    384   /**
    385    * The index of the start of the value of the Content-Encoding of the current
    386    * field.
    387    * Zero until the value is found.
    388    * Cannot be zero if any (including zero-length) filename available.
    389    */
    390   size_t enc_idx;
    391   /**
    392    * The length of the filename of the value of the Content-Encoding of
    393    * the current field, not including the terminating zero.
    394    * Zero until the length is found.
    395    */
    396   size_t enc_len;
    397 };
    398 
    399 /**
    400  * The "multipart/form-data" parsing data
    401  */
    402 struct mhd_PostParserMPartFormData
    403 {
    404   /**
    405    * The parsing state
    406    */
    407   enum mhd_PostMPartState st;
    408 
    409   /**
    410    * The field parsing data
    411    */
    412   struct mhd_PostParserMPartFieldData f;
    413 
    414   /**
    415    * Position of the first character when checking for the delimiter or for
    416    * the embedded header
    417    */
    418   size_t line_start;
    419 
    420   /**
    421    * The first position where the check for the delimiter has been started.
    422    * Should be CR char (or bare LR if allowed).
    423    * If delimiter is not found, re-interpreted as part of the filed "value".
    424    * If delimiter is found, this position can be moved to the second character
    425    * if the first position of the delimiter is used to put zero-termination
    426    * of previous field "value".
    427    */
    428   size_t delim_check_start;
    429 
    430   /**
    431    * Multi-part delimited.
    432    * Consists of CRLF + "--" + boundary marker.
    433    */
    434   struct mhd_BufferConst delim;
    435 };
    436 
    437 
    438 /**
    439  * The states of the "text/plain" parsing
    440  */
    441 enum MHD_FIXED_ENUM_ mhd_PostTextState
    442 {
    443   /**
    444    * The line processing has not been started yet
    445    */
    446   mhd_POST_TEXT_ST_NOT_STARTED = 0
    447   ,
    448   /**
    449    * Processing name of the field
    450    */
    451   mhd_POST_TEXT_ST_NAME
    452   ,
    453   /**
    454    * At the '=' character after the name.
    455    * This is an intermediate state, should be processed and switched to the next
    456    * state immediately.
    457    * Should not be used outside processing loop.
    458    */
    459   mhd_POST_TEXT_ST_AT_EQ
    460   ,
    461   /**
    462    * The '=' character after the name has been found.
    463    * Looking for the first value character.
    464    */
    465   mhd_POST_TEXT_ST_EQ_FOUND
    466   ,
    467   /**
    468    * Processing the value of the field.
    469    */
    470   mhd_POST_TEXT_ST_VALUE
    471   ,
    472   /**
    473    * At the CR character.
    474    * This is an intermediate state, should be processed and switched to the next
    475    * state immediately.
    476    * Should not be used outside processing loop.
    477    */
    478   mhd_POST_TEXT_ST_AT_CR
    479   ,
    480   /**
    481    * Looking for LF character after CR character.
    482    */
    483   mhd_POST_TEXT_ST_CR_FOUND
    484   ,
    485   /**
    486    * At the LF character without preceding CR character.
    487    * This is an intermediate state, should be processed and switched to the next
    488    * state immediately.
    489    * Should not be used outside processing loop.
    490    */
    491   mhd_POST_TEXT_ST_AT_LF_BARE
    492   ,
    493   /**
    494    * End of the line found.
    495    * This is an intermediate state, should be processed and switched to the next
    496    * state immediately.
    497    * Should not be used outside processing loop.
    498    */
    499   mhd_POST_TEXT_ST_FULL_LINE_FOUND
    500 };
    501 
    502 /**
    503  * The "text/plain" parsing data
    504  */
    505 struct mhd_PostParserTextData
    506 {
    507   /**
    508    * The parsing state
    509    */
    510   enum mhd_PostTextState st;
    511 
    512   /**
    513    * The index of the start of the name.
    514    */
    515   size_t name_idx;
    516 
    517   /**
    518    * The length of the name of the current field, not including
    519    * the terminating zero.
    520    * Zero until the length is found.
    521    */
    522   size_t name_len;
    523 
    524   /**
    525    * The index of the start of the value.
    526    * Zero until the value is found.
    527    * Cannot be zero if any (including zero-length) value available.
    528    */
    529   size_t value_idx;
    530 
    531   /**
    532    * The length of the value of the current field, not including
    533    * the terminating zero.
    534    * Zero until the length is found.
    535    */
    536   size_t value_len;
    537 };
    538 
    539 
    540 /**
    541  * The encoding-specific parsing data
    542  */
    543 union mhd_PostParserDetailedData
    544 {
    545   /**
    546    * The "application/x-www-form-urlencoded" parsing data
    547    */
    548   struct mhd_PostParserUrlEncData u_enc;
    549 
    550   /**
    551    * The "multipart/form-data" parsing data
    552    */
    553   struct mhd_PostParserMPartFormData m_form;
    554 
    555   /**
    556    * The "text/plain" parsing data
    557    */
    558   struct mhd_PostParserTextData text;
    559 };
    560 
    561 // TODO: remove?
    562 /**
    563  * The type of partially processed data in the buffer
    564  */
    565 enum MHD_FIXED_ENUM_ mhd_PostParserPartProcType
    566 {
    567   /**
    568    * No data in the buffer
    569    */
    570   mhd_POST_PARSER_PART_PROC_TYPE_NONE = 0
    571   ,
    572   /**
    573    * The data is partially processed name
    574    */
    575   mhd_POST_PARSER_PART_PROC_TYPE_NAME
    576   ,
    577   /**
    578    * The data is partially processed value
    579    */
    580   mhd_POST_PARSER_PART_PROC_TYPE_VALUE
    581 };
    582 
    583 // TODO: remove?
    584 /**
    585  * Buffered partially processed data
    586  */
    587 struct mhd_PostParserPartProcessedData
    588 {
    589   /**
    590    * Partially processed data, left from previous upload data portion
    591    */
    592   struct mhd_Buffer data;
    593 
    594   /**
    595    * The type of partially processed data in the @a data buffer
    596    */
    597   enum mhd_PostParserPartProcType d_type;
    598 };
    599 
    600 /**
    601  * The POST parsing data
    602  */
    603 struct mhd_PostParserData
    604 {
    605   /**
    606    * The result of parsing POST data
    607    */
    608   enum MHD_PostParseResult parse_result;
    609 
    610   /**
    611    * The type of POSE encoding is used.
    612    * Active member of @a e_d depends on this type.
    613    */
    614   enum MHD_HTTP_PostEncoding enc;
    615 
    616   /**
    617    * The encoding-specific parsing data
    618    */
    619   union mhd_PostParserDetailedData e_d;
    620 
    621   /**
    622    * The size of the data currently in the @a lbuf
    623    */
    624   size_t lbuf_used;
    625 
    626   /**
    627    * The maximum possible lbuf allocation size
    628    */
    629   size_t lbuf_limit;
    630 
    631   /**
    632    * True if any POST data was parsed successfully.
    633    */
    634   bool some_data_provided;
    635 
    636   /**
    637    * The start index of the current field.
    638    * If the field is processed by incremental callback, buffer can be freed or
    639    * reused up to this position (inclusive).
    640    */
    641   size_t field_start;
    642 
    643   /**
    644    * 'true' if current filed 'value' must be "streamed".
    645    */
    646   bool force_streamed;
    647 
    648   /**
    649    * The offset in the current value data.
    650    * Used when value is processed incrementally otherwise it is zero.
    651    */
    652   size_t value_off;
    653 
    654   /**
    655    * The position of the next character to be parsed
    656    */
    657   size_t next_parse_pos;
    658 };
    659 
    660 #endif /* ! MHD_POST_PARSER_H */