rage-iodine 1.8.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/ext/iodine/http.c +261 -114
 - data/ext/iodine/http.h +12 -18
 - data/ext/iodine/iodine_helpers.c +250 -0
 - data/ext/iodine/iodine_http.c +6 -0
 - data/ext/iodine/iodine_rack_io.c +1 -0
 - data/ext/iodine/iodine_rack_io.h +2 -0
 - data/ext/iodine/scheduler.c +17 -3
 - data/iodine.gemspec +0 -3
 - data/lib/iodine/version.rb +1 -1
 - data/lib/iodine.rb +1 -0
 - metadata +3 -5
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 14c91b97e06b90b30b47238df8eae6e431b1046bffb61758855a4a6f2fc647a4
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 284676ad696fca697d05a8ac7e0d4f8159f6bf4d34105efea653fa07cc705f19
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 5872a3cc209c22c85e6185a28e4a10dc5692426181766685580af260502dd09e6ff17f119b924a588d4a11a62c4e9a116e49640910219f4adf477e69914da590
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 748d34cfcf129ecdbcd0cc3c00c72f0ece4c3e18703478d3f503448955915a4577720e70d33c2e39eafd8f52ca9c80d154986fae477b5ffbe56745bacaac2347
         
     | 
    
        data/ext/iodine/http.c
    CHANGED
    
    | 
         @@ -19,6 +19,7 @@ Feel free to copy, use and enjoy according to the license provided. 
     | 
|
| 
       19 
19 
     | 
    
         
             
            #include <unistd.h>
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
            #include <pthread.h>
         
     | 
| 
      
 22 
     | 
    
         
            +
            #include <ruby/io.h>
         
     | 
| 
       22 
23 
     | 
    
         | 
| 
       23 
24 
     | 
    
         
             
            #ifndef HAVE_TM_TM_ZONE
         
     | 
| 
       24 
25 
     | 
    
         
             
            #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||     \
         
     | 
| 
         @@ -61,6 +62,13 @@ fio_tls_alpn_add(void *tls, const char *protocol_name, 
     | 
|
| 
       61 
62 
     | 
    
         
             
            #pragma weak fio_tls_alpn_add
         
     | 
| 
       62 
63 
     | 
    
         
             
            #endif
         
     | 
| 
       63 
64 
     | 
    
         | 
| 
      
 65 
     | 
    
         
            +
            static VALUE cTempfile;
         
     | 
| 
      
 66 
     | 
    
         
            +
            static VALUE tempfile_args;
         
     | 
| 
      
 67 
     | 
    
         
            +
            static VALUE cUploadedFile;
         
     | 
| 
      
 68 
     | 
    
         
            +
            static ID create_id;
         
     | 
| 
      
 69 
     | 
    
         
            +
            static ID path_id;
         
     | 
| 
      
 70 
     | 
    
         
            +
            static rb_encoding *IodineBinaryEncoding;
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
       64 
72 
     | 
    
         
             
            /* *****************************************************************************
         
     | 
| 
       65 
73 
     | 
    
         
             
            Small Helpers
         
     | 
| 
       66 
74 
     | 
    
         
             
            ***************************************************************************** */
         
     | 
| 
         @@ -1797,105 +1805,262 @@ typedef struct { 
     | 
|
| 
       1797 
1805 
     | 
    
         
             
              size_t pos;
         
     | 
| 
       1798 
1806 
     | 
    
         
             
              size_t partial_offset;
         
     | 
| 
       1799 
1807 
     | 
    
         
             
              size_t partial_length;
         
     | 
| 
       1800 
     | 
    
         
            -
               
     | 
| 
      
 1808 
     | 
    
         
            +
              VALUE partial_name;
         
     | 
| 
      
 1809 
     | 
    
         
            +
              int partial_fd;
         
     | 
| 
      
 1810 
     | 
    
         
            +
              VALUE partial_tempfile;
         
     | 
| 
      
 1811 
     | 
    
         
            +
              VALUE params;
         
     | 
| 
       1801 
1812 
     | 
    
         
             
            } http_fio_mime_s;
         
     | 
| 
       1802 
1813 
     | 
    
         | 
| 
       1803 
1814 
     | 
    
         
             
            #define http_mime_parser2fio(parser) ((http_fio_mime_s *)(parser))
         
     | 
| 
       1804 
1815 
     | 
    
         | 
| 
      
 1816 
     | 
    
         
            +
            /** Parse a parameter key and add it to the `params` hash. Check `parse_nested_query_internal` for reference. */
         
     | 
| 
      
 1817 
     | 
    
         
            +
            static void add_to_params(VALUE params, char *key, size_t key_len, VALUE value) {
         
     | 
| 
      
 1818 
     | 
    
         
            +
              char *pos = NULL;
         
     | 
| 
      
 1819 
     | 
    
         
            +
              if (key_len > 1) {
         
     | 
| 
      
 1820 
     | 
    
         
            +
                pos = memchr(key + 1, '[', key_len - 1);
         
     | 
| 
      
 1821 
     | 
    
         
            +
              }
         
     | 
| 
      
 1822 
     | 
    
         
            +
             
     | 
| 
      
 1823 
     | 
    
         
            +
              if (!pos) {
         
     | 
| 
      
 1824 
     | 
    
         
            +
                VALUE k = ID2SYM(rb_intern2(key, key_len));
         
     | 
| 
      
 1825 
     | 
    
         
            +
                rb_hash_aset(params, k, value);
         
     | 
| 
      
 1826 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 1827 
     | 
    
         
            +
                VALUE arr = Qnil, hsh = Qnil, hsh_key = Qnil;
         
     | 
| 
      
 1828 
     | 
    
         
            +
                VALUE k = ID2SYM(rb_intern2(key, pos - key));
         
     | 
| 
      
 1829 
     | 
    
         
            +
                char *k_pos, *end = key + key_len;
         
     | 
| 
      
 1830 
     | 
    
         
            +
                uint8_t depth = 0;
         
     | 
| 
      
 1831 
     | 
    
         
            +
             
     | 
| 
      
 1832 
     | 
    
         
            +
                while (pos < end) {
         
     | 
| 
      
 1833 
     | 
    
         
            +
                  if (depth++ == PARAMS_MAX_DEPTH) {
         
     | 
| 
      
 1834 
     | 
    
         
            +
                    rb_raise(rb_eRuntimeError, "Params too deep");
         
     | 
| 
      
 1835 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1836 
     | 
    
         
            +
             
     | 
| 
      
 1837 
     | 
    
         
            +
                  if (*pos == '[' && *(pos + 1) == ']') { // array
         
     | 
| 
      
 1838 
     | 
    
         
            +
                    if (arr != Qnil) {
         
     | 
| 
      
 1839 
     | 
    
         
            +
                      VALUE tmp = rb_ary_new();
         
     | 
| 
      
 1840 
     | 
    
         
            +
                      rb_ary_push(arr, tmp);
         
     | 
| 
      
 1841 
     | 
    
         
            +
                      arr = tmp;
         
     | 
| 
      
 1842 
     | 
    
         
            +
                    } else if (hsh != Qnil) {
         
     | 
| 
      
 1843 
     | 
    
         
            +
                      arr = rb_hash_aref(hsh, hsh_key);
         
     | 
| 
      
 1844 
     | 
    
         
            +
                      if (arr == Qnil) {
         
     | 
| 
      
 1845 
     | 
    
         
            +
                        arr = rb_ary_new();
         
     | 
| 
      
 1846 
     | 
    
         
            +
                        rb_hash_aset(hsh, hsh_key, arr);
         
     | 
| 
      
 1847 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 1848 
     | 
    
         
            +
                        Check_Type(arr, T_ARRAY);
         
     | 
| 
      
 1849 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1850 
     | 
    
         
            +
                      hsh = hsh_key = Qnil;
         
     | 
| 
      
 1851 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 1852 
     | 
    
         
            +
                      VALUE tmp = rb_hash_aref(params, k);
         
     | 
| 
      
 1853 
     | 
    
         
            +
                      if (tmp != Qnil) {
         
     | 
| 
      
 1854 
     | 
    
         
            +
                        Check_Type(tmp, T_ARRAY);
         
     | 
| 
      
 1855 
     | 
    
         
            +
                        arr = tmp;
         
     | 
| 
      
 1856 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 1857 
     | 
    
         
            +
                        arr = rb_ary_new();
         
     | 
| 
      
 1858 
     | 
    
         
            +
                        rb_hash_aset(params, k, arr);
         
     | 
| 
      
 1859 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1860 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1861 
     | 
    
         
            +
             
     | 
| 
      
 1862 
     | 
    
         
            +
                    pos += 2;
         
     | 
| 
      
 1863 
     | 
    
         
            +
             
     | 
| 
      
 1864 
     | 
    
         
            +
                  } else if (*pos == '[' && *(pos + 1) != ']') { // hash
         
     | 
| 
      
 1865 
     | 
    
         
            +
                    if (pos + 2 < end) {
         
     | 
| 
      
 1866 
     | 
    
         
            +
                      k_pos = memchr(pos + 2, ']', end - pos - 2);
         
     | 
| 
      
 1867 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 1868 
     | 
    
         
            +
                      k_pos = NULL;
         
     | 
| 
      
 1869 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1870 
     | 
    
         
            +
             
     | 
| 
      
 1871 
     | 
    
         
            +
                    if (!k_pos) {
         
     | 
| 
      
 1872 
     | 
    
         
            +
                      rb_raise(rb_eRuntimeError, "Bad params");
         
     | 
| 
      
 1873 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1874 
     | 
    
         
            +
             
     | 
| 
      
 1875 
     | 
    
         
            +
                    VALUE prev_hsh_key = hsh_key;
         
     | 
| 
      
 1876 
     | 
    
         
            +
                    hsh_key = ID2SYM(rb_intern2(pos + 1, k_pos - pos - 1));
         
     | 
| 
      
 1877 
     | 
    
         
            +
             
     | 
| 
      
 1878 
     | 
    
         
            +
                    if (hsh != Qnil) {
         
     | 
| 
      
 1879 
     | 
    
         
            +
                      VALUE existing = rb_hash_aref(hsh, prev_hsh_key);
         
     | 
| 
      
 1880 
     | 
    
         
            +
                      if (existing != Qnil) {
         
     | 
| 
      
 1881 
     | 
    
         
            +
                        Check_Type(existing, T_HASH);
         
     | 
| 
      
 1882 
     | 
    
         
            +
                        hsh = existing;
         
     | 
| 
      
 1883 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 1884 
     | 
    
         
            +
                        VALUE tmp = rb_hash_new();
         
     | 
| 
      
 1885 
     | 
    
         
            +
                        rb_hash_aset(hsh, prev_hsh_key, tmp);
         
     | 
| 
      
 1886 
     | 
    
         
            +
                        hsh = tmp;
         
     | 
| 
      
 1887 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1888 
     | 
    
         
            +
                    } else if (arr != Qnil) {
         
     | 
| 
      
 1889 
     | 
    
         
            +
                      VALUE nested_val = Qnil;
         
     | 
| 
      
 1890 
     | 
    
         
            +
                      if (RARRAY_LEN(arr) != 0) {
         
     | 
| 
      
 1891 
     | 
    
         
            +
                        VALUE tmp = rb_ary_entry(arr, -1);
         
     | 
| 
      
 1892 
     | 
    
         
            +
                        Check_Type(tmp, T_HASH);
         
     | 
| 
      
 1893 
     | 
    
         
            +
                        nested_val = rb_hash_aref(tmp, hsh_key);
         
     | 
| 
      
 1894 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1895 
     | 
    
         
            +
             
     | 
| 
      
 1896 
     | 
    
         
            +
                      if (RB_TYPE_P(nested_val, T_HASH)) {
         
     | 
| 
      
 1897 
     | 
    
         
            +
                        char *n_pos_start = k_pos + 1, *n_pos_end = k_pos + 1;
         
     | 
| 
      
 1898 
     | 
    
         
            +
             
     | 
| 
      
 1899 
     | 
    
         
            +
                        while (nested_val != Qnil && *n_pos_start == '[' && *(n_pos_start + 1) != ']' && *n_pos_end != '&' && *n_pos_end != '=' && n_pos_end < end) {
         
     | 
| 
      
 1900 
     | 
    
         
            +
                          n_pos_end++;
         
     | 
| 
      
 1901 
     | 
    
         
            +
             
     | 
| 
      
 1902 
     | 
    
         
            +
                          if (*n_pos_end == ']') {
         
     | 
| 
      
 1903 
     | 
    
         
            +
                            VALUE nested_key = ID2SYM(rb_intern2(n_pos_start + 1, n_pos_end - n_pos_start - 1));
         
     | 
| 
      
 1904 
     | 
    
         
            +
                            Check_Type(nested_val, T_HASH);
         
     | 
| 
      
 1905 
     | 
    
         
            +
                            nested_val = rb_hash_aref(nested_val, nested_key);
         
     | 
| 
      
 1906 
     | 
    
         
            +
                            n_pos_start = ++n_pos_end;
         
     | 
| 
      
 1907 
     | 
    
         
            +
                          }
         
     | 
| 
      
 1908 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1909 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1910 
     | 
    
         
            +
             
     | 
| 
      
 1911 
     | 
    
         
            +
                      if (RARRAY_LEN(arr) == 0 || nested_val != Qnil) {
         
     | 
| 
      
 1912 
     | 
    
         
            +
                        hsh = rb_hash_new();
         
     | 
| 
      
 1913 
     | 
    
         
            +
                        rb_ary_push(arr, hsh);
         
     | 
| 
      
 1914 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 1915 
     | 
    
         
            +
                        hsh = rb_ary_entry(arr, -1);
         
     | 
| 
      
 1916 
     | 
    
         
            +
                        if (hsh != Qnil) {
         
     | 
| 
      
 1917 
     | 
    
         
            +
                          Check_Type(hsh, T_HASH);
         
     | 
| 
      
 1918 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1919 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1920 
     | 
    
         
            +
             
     | 
| 
      
 1921 
     | 
    
         
            +
                      arr = Qnil;
         
     | 
| 
      
 1922 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 1923 
     | 
    
         
            +
                      VALUE tmp = rb_hash_aref(params, k);
         
     | 
| 
      
 1924 
     | 
    
         
            +
                      if (tmp != Qnil) {
         
     | 
| 
      
 1925 
     | 
    
         
            +
                        Check_Type(tmp, T_HASH);
         
     | 
| 
      
 1926 
     | 
    
         
            +
                        hsh = tmp;
         
     | 
| 
      
 1927 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 1928 
     | 
    
         
            +
                        hsh = rb_hash_new();
         
     | 
| 
      
 1929 
     | 
    
         
            +
                        rb_hash_aset(params, k, hsh);
         
     | 
| 
      
 1930 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1931 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1932 
     | 
    
         
            +
             
     | 
| 
      
 1933 
     | 
    
         
            +
                    pos = k_pos + 1;
         
     | 
| 
      
 1934 
     | 
    
         
            +
             
     | 
| 
      
 1935 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 1936 
     | 
    
         
            +
                    pos++;
         
     | 
| 
      
 1937 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1938 
     | 
    
         
            +
                }
         
     | 
| 
      
 1939 
     | 
    
         
            +
             
     | 
| 
      
 1940 
     | 
    
         
            +
                if (arr != Qnil) {
         
     | 
| 
      
 1941 
     | 
    
         
            +
                  rb_ary_push(arr, value);
         
     | 
| 
      
 1942 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 1943 
     | 
    
         
            +
                  rb_hash_aset(hsh, hsh_key, value);
         
     | 
| 
      
 1944 
     | 
    
         
            +
                }
         
     | 
| 
      
 1945 
     | 
    
         
            +
              }
         
     | 
| 
      
 1946 
     | 
    
         
            +
            }
         
     | 
| 
      
 1947 
     | 
    
         
            +
             
     | 
| 
      
 1948 
     | 
    
         
            +
            static inline void cleanup_temp_file(void *r_path) {
         
     | 
| 
      
 1949 
     | 
    
         
            +
              char *path = StringValueCStr(r_path);
         
     | 
| 
      
 1950 
     | 
    
         
            +
              IodineStore.remove((VALUE)r_path);
         
     | 
| 
      
 1951 
     | 
    
         
            +
              unlink(path);
         
     | 
| 
      
 1952 
     | 
    
         
            +
            }
         
     | 
| 
      
 1953 
     | 
    
         
            +
             
     | 
| 
      
 1954 
     | 
    
         
            +
            static VALUE create_temp_file(http_mime_parser_s *parser, char **path) {
         
     | 
| 
      
 1955 
     | 
    
         
            +
              VALUE tempfile = rb_funcallv_kw(cTempfile, create_id, 1, &tempfile_args, RB_PASS_KEYWORDS);
         
     | 
| 
      
 1956 
     | 
    
         
            +
             
     | 
| 
      
 1957 
     | 
    
         
            +
              VALUE r_path = rb_funcall2(tempfile, path_id, 0, NULL);
         
     | 
| 
      
 1958 
     | 
    
         
            +
              IodineStore.add(r_path);
         
     | 
| 
      
 1959 
     | 
    
         
            +
              *path = StringValueCStr(r_path);
         
     | 
| 
      
 1960 
     | 
    
         
            +
             
     | 
| 
      
 1961 
     | 
    
         
            +
              http_s *h = http_mime_parser2fio(parser)->h;
         
     | 
| 
      
 1962 
     | 
    
         
            +
              http_fio_protocol_s *p = (http_fio_protocol_s *)h->private_data.flag;
         
     | 
| 
      
 1963 
     | 
    
         
            +
              fio_uuid_link(p->uuid, (void *)r_path, cleanup_temp_file); // schedule file deletion
         
     | 
| 
      
 1964 
     | 
    
         
            +
              
         
     | 
| 
      
 1965 
     | 
    
         
            +
              return tempfile;
         
     | 
| 
      
 1966 
     | 
    
         
            +
            }
         
     | 
| 
      
 1967 
     | 
    
         
            +
             
     | 
| 
      
 1968 
     | 
    
         
            +
            static VALUE build_file_value(VALUE file, char *filename, size_t filename_len, char *mimetype, size_t mimetype_len) {
         
     | 
| 
      
 1969 
     | 
    
         
            +
              VALUE args[3] = { file, rb_enc_str_new(filename, filename_len, IodineBinaryEncoding), rb_enc_str_new(mimetype, mimetype_len, IodineBinaryEncoding) };
         
     | 
| 
      
 1970 
     | 
    
         
            +
              VALUE uploaded_file = rb_class_new_instance(3, args, cUploadedFile);
         
     | 
| 
      
 1971 
     | 
    
         
            +
             
     | 
| 
      
 1972 
     | 
    
         
            +
              return uploaded_file;
         
     | 
| 
      
 1973 
     | 
    
         
            +
            }
         
     | 
| 
      
 1974 
     | 
    
         
            +
             
     | 
| 
       1805 
1975 
     | 
    
         
             
            /** Called when all the data is available at once. */
         
     | 
| 
       1806 
1976 
     | 
    
         
             
            static void http_mime_parser_on_data(http_mime_parser_s *parser, void *name,
         
     | 
| 
       1807 
1977 
     | 
    
         
             
                                                 size_t name_len, void *filename,
         
     | 
| 
       1808 
1978 
     | 
    
         
             
                                                 size_t filename_len, void *mimetype,
         
     | 
| 
       1809 
1979 
     | 
    
         
             
                                                 size_t mimetype_len, void *value,
         
     | 
| 
       1810 
1980 
     | 
    
         
             
                                                 size_t value_len) {
         
     | 
| 
      
 1981 
     | 
    
         
            +
              // for regular values - just add them to params
         
     | 
| 
       1811 
1982 
     | 
    
         
             
              if (!filename_len) {
         
     | 
| 
       1812 
     | 
    
         
            -
                 
     | 
| 
       1813 
     | 
    
         
            -
             
     | 
| 
      
 1983 
     | 
    
         
            +
                VALUE r_value = rb_enc_str_new(value, value_len, IodineBinaryEncoding);
         
     | 
| 
      
 1984 
     | 
    
         
            +
                add_to_params(http_mime_parser2fio(parser)->params, name, name_len, r_value);
         
     | 
| 
       1814 
1985 
     | 
    
         
             
                return;
         
     | 
| 
       1815 
1986 
     | 
    
         
             
              }
         
     | 
| 
       1816 
     | 
    
         
            -
             
     | 
| 
       1817 
     | 
    
         
            -
               
     | 
| 
       1818 
     | 
    
         
            -
               
     | 
| 
       1819 
     | 
    
         
            -
               
     | 
| 
       1820 
     | 
    
         
            -
             
     | 
| 
       1821 
     | 
    
         
            -
               
     | 
| 
       1822 
     | 
    
         
            -
               
     | 
| 
       1823 
     | 
    
         
            -
               
     | 
| 
       1824 
     | 
    
         
            -
             
     | 
| 
       1825 
     | 
    
         
            -
             
     | 
| 
       1826 
     | 
    
         
            -
               
     | 
| 
       1827 
     | 
    
         
            -
                fiobj_str_resize(n, name_len);
         
     | 
| 
       1828 
     | 
    
         
            -
                fiobj_str_write(n, "[type]", 6);
         
     | 
| 
       1829 
     | 
    
         
            -
                tmp = fiobj_obj2cstr(n);
         
     | 
| 
       1830 
     | 
    
         
            -
                http_add2hash(http_mime_parser2fio(parser)->h->params, tmp.data, tmp.len,
         
     | 
| 
       1831 
     | 
    
         
            -
                              mimetype, mimetype_len, 0);
         
     | 
| 
       1832 
     | 
    
         
            -
              }
         
     | 
| 
       1833 
     | 
    
         
            -
              fiobj_free(n);
         
     | 
| 
      
 1987 
     | 
    
         
            +
             
     | 
| 
      
 1988 
     | 
    
         
            +
              // write file data into a temporary file
         
     | 
| 
      
 1989 
     | 
    
         
            +
              char* path;
         
     | 
| 
      
 1990 
     | 
    
         
            +
              VALUE r_tempfile = create_temp_file(parser, &path);
         
     | 
| 
      
 1991 
     | 
    
         
            +
             
     | 
| 
      
 1992 
     | 
    
         
            +
              int file = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0777);
         
     | 
| 
      
 1993 
     | 
    
         
            +
              write(file, value, value_len);
         
     | 
| 
      
 1994 
     | 
    
         
            +
              close(file);
         
     | 
| 
      
 1995 
     | 
    
         
            +
             
     | 
| 
      
 1996 
     | 
    
         
            +
              VALUE r_value = build_file_value(r_tempfile, filename, filename_len, mimetype, mimetype_len);
         
     | 
| 
      
 1997 
     | 
    
         
            +
              add_to_params(http_mime_parser2fio(parser)->params, name, name_len, r_value);
         
     | 
| 
       1834 
1998 
     | 
    
         
             
            }
         
     | 
| 
       1835 
1999 
     | 
    
         | 
| 
       1836 
2000 
     | 
    
         
             
            /** Called when the data didn't fit in the buffer. Data will be streamed. */
         
     | 
| 
       1837 
2001 
     | 
    
         
             
            static void http_mime_parser_on_partial_start(
         
     | 
| 
       1838 
2002 
     | 
    
         
             
                http_mime_parser_s *parser, void *name, size_t name_len, void *filename,
         
     | 
| 
       1839 
2003 
     | 
    
         
             
                size_t filename_len, void *mimetype, size_t mimetype_len) {
         
     | 
| 
       1840 
     | 
    
         
            -
             
     | 
| 
       1841 
     | 
    
         
            -
               
     | 
| 
       1842 
     | 
    
         
            -
              http_mime_parser2fio(parser)->partial_name =  
     | 
| 
      
 2004 
     | 
    
         
            +
             
     | 
| 
      
 2005 
     | 
    
         
            +
              // store the parameter name
         
     | 
| 
      
 2006 
     | 
    
         
            +
              http_mime_parser2fio(parser)->partial_name = rb_str_new(name, name_len);
         
     | 
| 
       1843 
2007 
     | 
    
         | 
| 
       1844 
2008 
     | 
    
         
             
              if (!filename)
         
     | 
| 
       1845 
2009 
     | 
    
         
             
                return;
         
     | 
| 
       1846 
2010 
     | 
    
         | 
| 
       1847 
     | 
    
         
            -
               
     | 
| 
       1848 
     | 
    
         
            -
               
     | 
| 
       1849 
     | 
    
         
            -
             
     | 
| 
       1850 
     | 
    
         
            -
              http_add2hash(http_mime_parser2fio(parser)->h->params, tmp.data, tmp.len,
         
     | 
| 
       1851 
     | 
    
         
            -
                            mimetype, mimetype_len, 0);
         
     | 
| 
      
 2011 
     | 
    
         
            +
              // create and store the temporary file for the file data
         
     | 
| 
      
 2012 
     | 
    
         
            +
              char* path;
         
     | 
| 
      
 2013 
     | 
    
         
            +
              VALUE r_tempfile = create_temp_file(parser, &path);
         
     | 
| 
       1852 
2014 
     | 
    
         | 
| 
       1853 
     | 
    
         
            -
               
     | 
| 
       1854 
     | 
    
         
            -
               
     | 
| 
       1855 
     | 
    
         
            -
               
     | 
| 
       1856 
     | 
    
         
            -
               
     | 
| 
       1857 
     | 
    
         
            -
                            filename, filename_len, 0);
         
     | 
| 
       1858 
     | 
    
         
            -
             
     | 
| 
       1859 
     | 
    
         
            -
              fiobj_str_resize(http_mime_parser2fio(parser)->partial_name, name_len);
         
     | 
| 
       1860 
     | 
    
         
            -
              fiobj_str_write(http_mime_parser2fio(parser)->partial_name, "[data]", 6);
         
     | 
| 
      
 2015 
     | 
    
         
            +
              http_mime_parser2fio(parser)->partial_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0777);
         
     | 
| 
      
 2016 
     | 
    
         
            +
              
         
     | 
| 
      
 2017 
     | 
    
         
            +
              VALUE r_value = build_file_value(r_tempfile, filename, filename_len, mimetype, mimetype_len);
         
     | 
| 
      
 2018 
     | 
    
         
            +
              http_mime_parser2fio(parser)->partial_tempfile = r_value;
         
     | 
| 
       1861 
2019 
     | 
    
         
             
            }
         
     | 
| 
       1862 
2020 
     | 
    
         | 
| 
       1863 
2021 
     | 
    
         
             
            /** Called when partial data is available. */
         
     | 
| 
       1864 
2022 
     | 
    
         
             
            static void http_mime_parser_on_partial_data(http_mime_parser_s *parser,
         
     | 
| 
       1865 
2023 
     | 
    
         
             
                                                         void *value, size_t value_len) {
         
     | 
| 
       1866 
     | 
    
         
            -
             
     | 
| 
       1867 
     | 
    
         
            -
             
     | 
| 
       1868 
     | 
    
         
            -
             
     | 
| 
       1869 
     | 
    
         
            -
             
     | 
| 
       1870 
     | 
    
         
            -
             
     | 
| 
       1871 
     | 
    
         
            -
             
     | 
| 
       1872 
     | 
    
         
            -
             
     | 
| 
      
 2024 
     | 
    
         
            +
             
     | 
| 
      
 2025 
     | 
    
         
            +
              http_fio_mime_s *fio_parser = http_mime_parser2fio(parser);
         
     | 
| 
      
 2026 
     | 
    
         
            +
             
     | 
| 
      
 2027 
     | 
    
         
            +
              // if this is a file - write into it rightaway
         
     | 
| 
      
 2028 
     | 
    
         
            +
              if (fio_parser->partial_fd) {
         
     | 
| 
      
 2029 
     | 
    
         
            +
                write(fio_parser->partial_fd, value, value_len);
         
     | 
| 
      
 2030 
     | 
    
         
            +
                return;
         
     | 
| 
      
 2031 
     | 
    
         
            +
              }
         
     | 
| 
      
 2032 
     | 
    
         
            +
             
     | 
| 
      
 2033 
     | 
    
         
            +
              // if that's just a large piece of data - store the offset and length values
         
     | 
| 
      
 2034 
     | 
    
         
            +
              if (!fio_parser->partial_offset) {
         
     | 
| 
      
 2035 
     | 
    
         
            +
                fio_parser->partial_offset = fio_parser->pos + ((uintptr_t)value - (uintptr_t)fio_parser->buffer.data);
         
     | 
| 
      
 2036 
     | 
    
         
            +
              }
         
     | 
| 
      
 2037 
     | 
    
         
            +
              fio_parser->partial_length += value_len;
         
     | 
| 
       1873 
2038 
     | 
    
         
             
            }
         
     | 
| 
       1874 
2039 
     | 
    
         | 
| 
       1875 
2040 
     | 
    
         
             
            /** Called when the partial data is complete. */
         
     | 
| 
       1876 
2041 
     | 
    
         
             
            static void http_mime_parser_on_partial_end(http_mime_parser_s *parser) {
         
     | 
| 
      
 2042 
     | 
    
         
            +
              http_fio_mime_s *fio_parser = http_mime_parser2fio(parser);
         
     | 
| 
      
 2043 
     | 
    
         
            +
             
     | 
| 
      
 2044 
     | 
    
         
            +
              // for a file - add to params and close the fd
         
     | 
| 
      
 2045 
     | 
    
         
            +
              if (fio_parser->partial_fd) {
         
     | 
| 
      
 2046 
     | 
    
         
            +
                add_to_params(fio_parser->params, RSTRING_PTR(fio_parser->partial_name), RSTRING_LEN(fio_parser->partial_name), fio_parser->partial_tempfile);
         
     | 
| 
      
 2047 
     | 
    
         
            +
                close(fio_parser->partial_fd);
         
     | 
| 
      
 2048 
     | 
    
         
            +
             
     | 
| 
      
 2049 
     | 
    
         
            +
                fio_parser->partial_name = Qnil;
         
     | 
| 
      
 2050 
     | 
    
         
            +
                fio_parser->partial_tempfile = Qnil;
         
     | 
| 
      
 2051 
     | 
    
         
            +
                fio_parser->partial_fd = 0;
         
     | 
| 
       1877 
2052 
     | 
    
         | 
| 
       1878 
     | 
    
         
            -
              fio_str_info_s tmp =
         
     | 
| 
       1879 
     | 
    
         
            -
                  fiobj_obj2cstr(http_mime_parser2fio(parser)->partial_name);
         
     | 
| 
       1880 
     | 
    
         
            -
              FIOBJ o = FIOBJ_INVALID;
         
     | 
| 
       1881 
     | 
    
         
            -
              if (!http_mime_parser2fio(parser)->partial_length)
         
     | 
| 
       1882 
2053 
     | 
    
         
             
                return;
         
     | 
| 
       1883 
     | 
    
         
            -
              if (http_mime_parser2fio(parser)->partial_length < 42) {
         
     | 
| 
       1884 
     | 
    
         
            -
                /* short data gets a new object */
         
     | 
| 
       1885 
     | 
    
         
            -
                o = fiobj_str_new(http_mime_parser2fio(parser)->buffer.data +
         
     | 
| 
       1886 
     | 
    
         
            -
                                      http_mime_parser2fio(parser)->partial_offset,
         
     | 
| 
       1887 
     | 
    
         
            -
                                  http_mime_parser2fio(parser)->partial_length);
         
     | 
| 
       1888 
     | 
    
         
            -
              } else {
         
     | 
| 
       1889 
     | 
    
         
            -
                /* longer data gets a reference object (memory collision concerns) */
         
     | 
| 
       1890 
     | 
    
         
            -
                o = fiobj_data_slice(http_mime_parser2fio(parser)->h->body,
         
     | 
| 
       1891 
     | 
    
         
            -
                                     http_mime_parser2fio(parser)->partial_offset,
         
     | 
| 
       1892 
     | 
    
         
            -
                                     http_mime_parser2fio(parser)->partial_length);
         
     | 
| 
       1893 
2054 
     | 
    
         
             
              }
         
     | 
| 
       1894 
     | 
    
         
            -
             
     | 
| 
       1895 
     | 
    
         
            -
             
     | 
| 
       1896 
     | 
    
         
            -
               
     | 
| 
       1897 
     | 
    
         
            -
               
     | 
| 
       1898 
     | 
    
         
            -
               
     | 
| 
      
 2055 
     | 
    
         
            +
             
     | 
| 
      
 2056 
     | 
    
         
            +
              FIOBJ slice = fiobj_data_slice(fio_parser->h->body, fio_parser->partial_offset, fio_parser->partial_length);
         
     | 
| 
      
 2057 
     | 
    
         
            +
              fio_str_info_s s_slice = fiobj_obj2cstr(slice);
         
     | 
| 
      
 2058 
     | 
    
         
            +
              VALUE r_value = rb_enc_str_new(s_slice.data, s_slice.len, IodineBinaryEncoding);
         
     | 
| 
      
 2059 
     | 
    
         
            +
              add_to_params(fio_parser->params, RSTRING_PTR(fio_parser->partial_name), RSTRING_LEN(fio_parser->partial_name), r_value);
         
     | 
| 
      
 2060 
     | 
    
         
            +
             
     | 
| 
      
 2061 
     | 
    
         
            +
              fio_parser->partial_name = Qnil;
         
     | 
| 
      
 2062 
     | 
    
         
            +
              fio_parser->partial_length = 0;
         
     | 
| 
      
 2063 
     | 
    
         
            +
              fio_parser->partial_offset = 0;
         
     | 
| 
       1899 
2064 
     | 
    
         
             
            }
         
     | 
| 
       1900 
2065 
     | 
    
         | 
| 
       1901 
2066 
     | 
    
         
             
            /**
         
     | 
| 
         @@ -1911,65 +2076,29 @@ static inline size_t http_mime_decode_url(char *dest, const char *encoded, 
     | 
|
| 
       1911 
2076 
     | 
    
         
             
            }
         
     | 
| 
       1912 
2077 
     | 
    
         | 
| 
       1913 
2078 
     | 
    
         
             
            /**
         
     | 
| 
       1914 
     | 
    
         
            -
             * Attempts to decode  
     | 
| 
       1915 
     | 
    
         
            -
             *
         
     | 
| 
       1916 
     | 
    
         
            -
             * Supported Types include:
         
     | 
| 
       1917 
     | 
    
         
            -
             * * application/x-www-form-urlencoded
         
     | 
| 
       1918 
     | 
    
         
            -
             * * application/json
         
     | 
| 
       1919 
     | 
    
         
            -
             * * multipart/form-data
         
     | 
| 
      
 2079 
     | 
    
         
            +
             * Attempts to decode a multipart/form-data encoded body.
         
     | 
| 
       1920 
2080 
     | 
    
         
             
             */
         
     | 
| 
       1921 
     | 
    
         
            -
             
     | 
| 
       1922 
     | 
    
         
            -
              static  
     | 
| 
       1923 
     | 
    
         
            -
              if (! 
     | 
| 
       1924 
     | 
    
         
            -
                 
     | 
| 
       1925 
     | 
    
         
            -
             
     | 
| 
       1926 
     | 
    
         
            -
                content_type_hash = fiobj_hash_string("content-type", 12);
         
     | 
| 
       1927 
     | 
    
         
            -
              FIOBJ ct = fiobj_hash_get2(h->headers, content_type_hash);
         
     | 
| 
       1928 
     | 
    
         
            -
              fio_str_info_s content_type = fiobj_obj2cstr(ct);
         
     | 
| 
       1929 
     | 
    
         
            -
              if (content_type.len < 16)
         
     | 
| 
       1930 
     | 
    
         
            -
                return -1;
         
     | 
| 
       1931 
     | 
    
         
            -
              if (content_type.len >= 33 &&
         
     | 
| 
       1932 
     | 
    
         
            -
                  !strncasecmp("application/x-www-form-urlencoded", content_type.data,
         
     | 
| 
       1933 
     | 
    
         
            -
                               33)) {
         
     | 
| 
       1934 
     | 
    
         
            -
                if (!h->params)
         
     | 
| 
       1935 
     | 
    
         
            -
                  h->params = fiobj_hash_new();
         
     | 
| 
       1936 
     | 
    
         
            -
                FIOBJ tmp = h->query;
         
     | 
| 
       1937 
     | 
    
         
            -
                h->query = h->body;
         
     | 
| 
       1938 
     | 
    
         
            -
                http_parse_query(h);
         
     | 
| 
       1939 
     | 
    
         
            -
                h->query = tmp;
         
     | 
| 
       1940 
     | 
    
         
            -
                return 0;
         
     | 
| 
       1941 
     | 
    
         
            -
              }
         
     | 
| 
       1942 
     | 
    
         
            -
              if (content_type.len >= 16 &&
         
     | 
| 
       1943 
     | 
    
         
            -
                  !strncasecmp("application/json", content_type.data, 16)) {
         
     | 
| 
       1944 
     | 
    
         
            -
                content_type = fiobj_obj2cstr(h->body);
         
     | 
| 
       1945 
     | 
    
         
            -
                if (h->params)
         
     | 
| 
       1946 
     | 
    
         
            -
                  return -1;
         
     | 
| 
       1947 
     | 
    
         
            -
                if (fiobj_json2obj(&h->params, content_type.data, content_type.len) == 0)
         
     | 
| 
       1948 
     | 
    
         
            -
                  return -1;
         
     | 
| 
       1949 
     | 
    
         
            -
                if (FIOBJ_TYPE_IS(h->params, FIOBJ_T_HASH))
         
     | 
| 
       1950 
     | 
    
         
            -
                  return 0;
         
     | 
| 
       1951 
     | 
    
         
            -
                FIOBJ tmp = h->params;
         
     | 
| 
       1952 
     | 
    
         
            -
                FIOBJ key = fiobj_str_new("JSON", 4);
         
     | 
| 
       1953 
     | 
    
         
            -
                h->params = fiobj_hash_new2(4);
         
     | 
| 
       1954 
     | 
    
         
            -
                fiobj_hash_set(h->params, key, tmp);
         
     | 
| 
       1955 
     | 
    
         
            -
                fiobj_free(key);
         
     | 
| 
       1956 
     | 
    
         
            -
                return 0;
         
     | 
| 
      
 2081 
     | 
    
         
            +
            VALUE http_parse_multipart(http_s *h, char *content_type, size_t content_type_len) {
         
     | 
| 
      
 2082 
     | 
    
         
            +
              static uint8_t http_initialized;
         
     | 
| 
      
 2083 
     | 
    
         
            +
              if (!http_initialized) {
         
     | 
| 
      
 2084 
     | 
    
         
            +
                http_initialized = 1;
         
     | 
| 
      
 2085 
     | 
    
         
            +
                http_init();
         
     | 
| 
       1957 
2086 
     | 
    
         
             
              }
         
     | 
| 
       1958 
2087 
     | 
    
         | 
| 
       1959 
     | 
    
         
            -
               
     | 
| 
       1960 
     | 
    
         
            -
               
     | 
| 
       1961 
     | 
    
         
            -
             
     | 
| 
       1962 
     | 
    
         
            -
             
     | 
| 
       1963 
     | 
    
         
            -
                h->params = fiobj_hash_new();
         
     | 
| 
      
 2088 
     | 
    
         
            +
              VALUE params = rb_hash_new();
         
     | 
| 
      
 2089 
     | 
    
         
            +
              http_fio_mime_s p = {.h = h, .params = params};
         
     | 
| 
      
 2090 
     | 
    
         
            +
              if (http_mime_parser_init(&p.p, content_type, content_type_len))
         
     | 
| 
      
 2091 
     | 
    
         
            +
                rb_raise(rb_eRuntimeError, "Malformed multipart request");
         
     | 
| 
       1964 
2092 
     | 
    
         | 
| 
       1965 
2093 
     | 
    
         
             
              do {
         
     | 
| 
       1966 
2094 
     | 
    
         
             
                size_t cons = http_mime_parse(&p.p, p.buffer.data, p.buffer.len);
         
     | 
| 
       1967 
2095 
     | 
    
         
             
                p.pos += cons;
         
     | 
| 
       1968 
     | 
    
         
            -
                p.buffer = fiobj_data_pread(h->body, p.pos,  
     | 
| 
      
 2096 
     | 
    
         
            +
                p.buffer = fiobj_data_pread(h->body, p.pos, 262144);
         
     | 
| 
       1969 
2097 
     | 
    
         
             
              } while (p.buffer.data && !p.p.done && !p.p.error);
         
     | 
| 
       1970 
     | 
    
         
            -
               
     | 
| 
       1971 
     | 
    
         
            -
              p. 
     | 
| 
       1972 
     | 
    
         
            -
             
     | 
| 
      
 2098 
     | 
    
         
            +
              
         
     | 
| 
      
 2099 
     | 
    
         
            +
              p.params = Qnil;
         
     | 
| 
      
 2100 
     | 
    
         
            +
             
     | 
| 
      
 2101 
     | 
    
         
            +
              return params;
         
     | 
| 
       1973 
2102 
     | 
    
         
             
            }
         
     | 
| 
       1974 
2103 
     | 
    
         | 
| 
       1975 
2104 
     | 
    
         
             
            /* *****************************************************************************
         
     | 
| 
         @@ -2489,6 +2618,24 @@ ssize_t http_decode_path_unsafe(char *dest, const char *url_data) { 
     | 
|
| 
       2489 
2618 
     | 
    
         
             
              return pos - dest;
         
     | 
| 
       2490 
2619 
     | 
    
         
             
            }
         
     | 
| 
       2491 
2620 
     | 
    
         | 
| 
      
 2621 
     | 
    
         
            +
            // init the http module to enable multipart/form-data parsing;
         
     | 
| 
      
 2622 
     | 
    
         
            +
            // should be called lazily as it references `Rage`
         
     | 
| 
      
 2623 
     | 
    
         
            +
            void http_init(void) {
         
     | 
| 
      
 2624 
     | 
    
         
            +
              cTempfile = rb_const_get(rb_cObject, rb_intern("Tempfile"));
         
     | 
| 
      
 2625 
     | 
    
         
            +
             
     | 
| 
      
 2626 
     | 
    
         
            +
              VALUE cRage = rb_const_get(rb_cObject, rb_intern("Rage"));
         
     | 
| 
      
 2627 
     | 
    
         
            +
              cUploadedFile = rb_const_get(cRage, rb_intern("UploadedFile"));
         
     | 
| 
      
 2628 
     | 
    
         
            +
              
         
     | 
| 
      
 2629 
     | 
    
         
            +
              tempfile_args = rb_hash_new();
         
     | 
| 
      
 2630 
     | 
    
         
            +
              rb_hash_aset(tempfile_args, ID2SYM(rb_intern("binmode")), Qtrue);
         
     | 
| 
      
 2631 
     | 
    
         
            +
              rb_global_variable(&tempfile_args);
         
     | 
| 
      
 2632 
     | 
    
         
            +
             
     | 
| 
      
 2633 
     | 
    
         
            +
              create_id = rb_intern("create");
         
     | 
| 
      
 2634 
     | 
    
         
            +
              path_id = rb_intern("path");
         
     | 
| 
      
 2635 
     | 
    
         
            +
             
     | 
| 
      
 2636 
     | 
    
         
            +
              IodineBinaryEncoding = rb_enc_find("binary");
         
     | 
| 
      
 2637 
     | 
    
         
            +
            }
         
     | 
| 
      
 2638 
     | 
    
         
            +
             
     | 
| 
       2492 
2639 
     | 
    
         
             
            /* *****************************************************************************
         
     | 
| 
       2493 
2640 
     | 
    
         
             
            Lookup Tables / functions
         
     | 
| 
       2494 
2641 
     | 
    
         
             
            ***************************************************************************** */
         
     | 
    
        data/ext/iodine/http.h
    CHANGED
    
    | 
         @@ -7,6 +7,8 @@ Feel free to copy, use and enjoy according to the license provided. 
     | 
|
| 
       7 
7 
     | 
    
         
             
            */
         
     | 
| 
       8 
8 
     | 
    
         
             
            #define H_HTTP_H
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
      
 10 
     | 
    
         
            +
            #include "ruby.h"
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
       10 
12 
     | 
    
         
             
            #include <fio.h>
         
     | 
| 
       11 
13 
     | 
    
         | 
| 
       12 
14 
     | 
    
         
             
            #include <fiobj.h>
         
     | 
| 
         @@ -58,6 +60,10 @@ Compile Time Settings 
     | 
|
| 
       58 
60 
     | 
    
         
             
            #define FIO_HTTP_EXACT_LOGGING 0
         
     | 
| 
       59 
61 
     | 
    
         
             
            #endif
         
     | 
| 
       60 
62 
     | 
    
         | 
| 
      
 63 
     | 
    
         
            +
            #ifndef PARAMS_MAX_DEPTH
         
     | 
| 
      
 64 
     | 
    
         
            +
            #define PARAMS_MAX_DEPTH 5
         
     | 
| 
      
 65 
     | 
    
         
            +
            #endif
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
       61 
67 
     | 
    
         
             
            /** the `http_listen settings, see details in the struct definition. */
         
     | 
| 
       62 
68 
     | 
    
         
             
            typedef struct http_settings_s http_settings_s;
         
     | 
| 
       63 
69 
     | 
    
         | 
| 
         @@ -772,25 +778,9 @@ HTTP GET and POST parsing helpers 
     | 
|
| 
       772 
778 
     | 
    
         
             
            ***************************************************************************** */
         
     | 
| 
       773 
779 
     | 
    
         | 
| 
       774 
780 
     | 
    
         
             
            /**
         
     | 
| 
       775 
     | 
    
         
            -
             * Attempts to decode  
     | 
| 
       776 
     | 
    
         
            -
             *
         
     | 
| 
       777 
     | 
    
         
            -
             * Supported Types include:
         
     | 
| 
       778 
     | 
    
         
            -
             * * application/x-www-form-urlencoded
         
     | 
| 
       779 
     | 
    
         
            -
             * * application/json
         
     | 
| 
       780 
     | 
    
         
            -
             * * multipart/form-data
         
     | 
| 
       781 
     | 
    
         
            -
             *
         
     | 
| 
       782 
     | 
    
         
            -
             * This should be called before `http_parse_query`, in order to support JSON
         
     | 
| 
       783 
     | 
    
         
            -
             * data.
         
     | 
| 
       784 
     | 
    
         
            -
             *
         
     | 
| 
       785 
     | 
    
         
            -
             * If the JSON data isn't an object, it will be saved under the key "JSON" in
         
     | 
| 
       786 
     | 
    
         
            -
             * the `params` hash.
         
     | 
| 
       787 
     | 
    
         
            -
             *
         
     | 
| 
       788 
     | 
    
         
            -
             * If the `multipart/form-data` type contains JSON files, they will NOT be
         
     | 
| 
       789 
     | 
    
         
            -
             * parsed (they will behave like any other file, with `data`, `type` and
         
     | 
| 
       790 
     | 
    
         
            -
             * `filename` keys assigned). This allows non-object JSON data (such as array)
         
     | 
| 
       791 
     | 
    
         
            -
             * to be handled by the app.
         
     | 
| 
      
 781 
     | 
    
         
            +
             * Attempts to decode a multipart/form-data encoded body.
         
     | 
| 
       792 
782 
     | 
    
         
             
             */
         
     | 
| 
       793 
     | 
    
         
            -
             
     | 
| 
      
 783 
     | 
    
         
            +
            VALUE http_parse_multipart(http_s *h, char *content_type, size_t content_type_len);
         
     | 
| 
       794 
784 
     | 
    
         | 
| 
       795 
785 
     | 
    
         
             
            /**
         
     | 
| 
       796 
786 
     | 
    
         
             
             * Parses the query part of an HTTP request/response. Uses `http_add2hash`.
         
     | 
| 
         @@ -1007,6 +997,10 @@ typedef fio_url_s http_url_s 
     | 
|
| 
       1007 
997 
     | 
    
         
             
             */
         
     | 
| 
       1008 
998 
     | 
    
         
             
            #define http_url_parse(url, len) fio_url_parse((url), (len))
         
     | 
| 
       1009 
999 
     | 
    
         | 
| 
      
 1000 
     | 
    
         
            +
            // init the http module to enable multipart/form-data parsing;
         
     | 
| 
      
 1001 
     | 
    
         
            +
            // should be called lazily as it references `Rage`
         
     | 
| 
      
 1002 
     | 
    
         
            +
            void http_init(void);
         
     | 
| 
      
 1003 
     | 
    
         
            +
             
     | 
| 
       1010 
1004 
     | 
    
         
             
            #if DEBUG
         
     | 
| 
       1011 
1005 
     | 
    
         
             
            void http_tests(void);
         
     | 
| 
       1012 
1006 
     | 
    
         
             
            #endif
         
     | 
    
        data/ext/iodine/iodine_helpers.c
    CHANGED
    
    | 
         @@ -209,6 +209,253 @@ static VALUE iodine_rfc2109(VALUE self, VALUE rtm) { 
     | 
|
| 
       209 
209 
     | 
    
         
             
              (void)self;
         
     | 
| 
       210 
210 
     | 
    
         
             
            }
         
     | 
| 
       211 
211 
     | 
    
         | 
| 
      
 212 
     | 
    
         
            +
            /**
         
     | 
| 
      
 213 
     | 
    
         
            +
            Convert query string into a Ruby object in (almost always) one pass with no recursion.
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
                    Iodine::Rack::Utils.parse_nested_query("a=1&b[]=2&c[d]=3") # => { "a" => "1", "b" => ["2"], "c" => { "d" => "3" } }
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
                    query = "a=1&b[]=2&c[d]=3"
         
     | 
| 
      
 221 
     | 
    
         
            +
                    Benchmark.ips do |x|
         
     | 
| 
      
 222 
     | 
    
         
            +
                      x.report("Iodine") {
         
     | 
| 
      
 223 
     | 
    
         
            +
                        Iodine::Rack::Utils.parse_nested_query(query)
         
     | 
| 
      
 224 
     | 
    
         
            +
                      }
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                      x.report("Rack") {
         
     | 
| 
      
 227 
     | 
    
         
            +
                        Rack::Utils.parse_nested_query(query)
         
     | 
| 
      
 228 
     | 
    
         
            +
                      }
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                      x.compare!
         
     | 
| 
      
 231 
     | 
    
         
            +
                    end
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                    Calculating -------------------------------------
         
     | 
| 
      
 235 
     | 
    
         
            +
                          Iodine      1.088M (~ 1.1%) i/s -      5.526M in   5.077759s
         
     | 
| 
      
 236 
     | 
    
         
            +
                            Rack     64.258k (~ 1.0%) i/s -    321.657k in   5.006187s
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
                    Comparison:
         
     | 
| 
      
 239 
     | 
    
         
            +
                                  Iodine:  1088431.2 i/s
         
     | 
| 
      
 240 
     | 
    
         
            +
                                    Rack:    64257.9 i/s - 16.94x  slower
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
            */
         
     | 
| 
      
 243 
     | 
    
         
            +
            static VALUE parse_nested_query_internal(char *str, size_t len) {
         
     | 
| 
      
 244 
     | 
    
         
            +
              uint8_t should_decode = 0;
         
     | 
| 
      
 245 
     | 
    
         
            +
              VALUE params = rb_hash_new();
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
              char *pos = str, *k_pos = str, *v_pos = str;
         
     | 
| 
      
 248 
     | 
    
         
            +
              const char *end = str + len;
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
              while (pos < end) {
         
     | 
| 
      
 251 
     | 
    
         
            +
                k_pos++;
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
                if (*k_pos == '=') { // plain param
         
     | 
| 
      
 254 
     | 
    
         
            +
                  v_pos = k_pos + 1;
         
     | 
| 
      
 255 
     | 
    
         
            +
                  while (*v_pos != '&' && v_pos < end) {
         
     | 
| 
      
 256 
     | 
    
         
            +
                    if (*v_pos == '%' || *v_pos == '+') {
         
     | 
| 
      
 257 
     | 
    
         
            +
                      should_decode = 1;
         
     | 
| 
      
 258 
     | 
    
         
            +
                    }
         
     | 
| 
      
 259 
     | 
    
         
            +
                    v_pos++;
         
     | 
| 
      
 260 
     | 
    
         
            +
                  }
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
                  VALUE k = ID2SYM(rb_intern2(pos, k_pos - pos)), v = rb_str_new(k_pos + 1, v_pos - k_pos - 1);
         
     | 
| 
      
 263 
     | 
    
         
            +
                  if (should_decode) {
         
     | 
| 
      
 264 
     | 
    
         
            +
                    rb_hash_aset(params, k, url_decode_inplace(Qnil, v));
         
     | 
| 
      
 265 
     | 
    
         
            +
                    should_decode = 0;
         
     | 
| 
      
 266 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 267 
     | 
    
         
            +
                    rb_hash_aset(params, k, v);
         
     | 
| 
      
 268 
     | 
    
         
            +
                  }
         
     | 
| 
      
 269 
     | 
    
         
            +
                  pos = k_pos = v_pos + 1;
         
     | 
| 
      
 270 
     | 
    
         
            +
             
     | 
| 
      
 271 
     | 
    
         
            +
                } else if (*k_pos == '[') { // things are about to get rough now
         
     | 
| 
      
 272 
     | 
    
         
            +
                  VALUE arr = Qnil, hsh = Qnil, hsh_key = Qnil;
         
     | 
| 
      
 273 
     | 
    
         
            +
                  VALUE k = ID2SYM(rb_intern2(pos, k_pos - pos)), v;
         
     | 
| 
      
 274 
     | 
    
         
            +
                  pos = k_pos;
         
     | 
| 
      
 275 
     | 
    
         
            +
                  uint8_t depth = 0;
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
                  while (*pos != '=' && pos < end) {
         
     | 
| 
      
 278 
     | 
    
         
            +
                    if (depth++ == PARAMS_MAX_DEPTH) {
         
     | 
| 
      
 279 
     | 
    
         
            +
                      rb_raise(rb_eRuntimeError, "Params too deep");
         
     | 
| 
      
 280 
     | 
    
         
            +
                    }
         
     | 
| 
      
 281 
     | 
    
         
            +
             
     | 
| 
      
 282 
     | 
    
         
            +
                    if (*pos == '[' && *(pos + 1) == ']') { // array
         
     | 
| 
      
 283 
     | 
    
         
            +
                      if (arr != Qnil) {
         
     | 
| 
      
 284 
     | 
    
         
            +
                        VALUE tmp = rb_ary_new();
         
     | 
| 
      
 285 
     | 
    
         
            +
                        rb_ary_push(arr, tmp);
         
     | 
| 
      
 286 
     | 
    
         
            +
                        arr = tmp;
         
     | 
| 
      
 287 
     | 
    
         
            +
                      } else if (hsh != Qnil) {
         
     | 
| 
      
 288 
     | 
    
         
            +
                        arr = rb_hash_aref(hsh, hsh_key);
         
     | 
| 
      
 289 
     | 
    
         
            +
                        if (arr == Qnil) {
         
     | 
| 
      
 290 
     | 
    
         
            +
                          arr = rb_ary_new();
         
     | 
| 
      
 291 
     | 
    
         
            +
                          rb_hash_aset(hsh, hsh_key, arr);
         
     | 
| 
      
 292 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 293 
     | 
    
         
            +
                          Check_Type(arr, T_ARRAY);
         
     | 
| 
      
 294 
     | 
    
         
            +
                        }
         
     | 
| 
      
 295 
     | 
    
         
            +
                        hsh = hsh_key = Qnil;
         
     | 
| 
      
 296 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 297 
     | 
    
         
            +
                        VALUE tmp = rb_hash_aref(params, k);
         
     | 
| 
      
 298 
     | 
    
         
            +
                        if (tmp != Qnil) {
         
     | 
| 
      
 299 
     | 
    
         
            +
                          Check_Type(tmp, T_ARRAY);
         
     | 
| 
      
 300 
     | 
    
         
            +
                          arr = tmp;
         
     | 
| 
      
 301 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 302 
     | 
    
         
            +
                          arr = rb_ary_new();
         
     | 
| 
      
 303 
     | 
    
         
            +
                          rb_hash_aset(params, k, arr);
         
     | 
| 
      
 304 
     | 
    
         
            +
                        }
         
     | 
| 
      
 305 
     | 
    
         
            +
                      }
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
                      pos += 2;
         
     | 
| 
      
 308 
     | 
    
         
            +
             
     | 
| 
      
 309 
     | 
    
         
            +
                    } else if (*pos == '[' && *(pos + 1) != ']') { // hash
         
     | 
| 
      
 310 
     | 
    
         
            +
                      if (pos + 2 < end) {
         
     | 
| 
      
 311 
     | 
    
         
            +
                        k_pos = memchr(pos + 2, ']', end - pos - 2);
         
     | 
| 
      
 312 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 313 
     | 
    
         
            +
                        k_pos = NULL;
         
     | 
| 
      
 314 
     | 
    
         
            +
                      }
         
     | 
| 
      
 315 
     | 
    
         
            +
             
     | 
| 
      
 316 
     | 
    
         
            +
                      if (!k_pos) {
         
     | 
| 
      
 317 
     | 
    
         
            +
                        rb_raise(rb_eRuntimeError, "Bad params");
         
     | 
| 
      
 318 
     | 
    
         
            +
                      }
         
     | 
| 
      
 319 
     | 
    
         
            +
             
     | 
| 
      
 320 
     | 
    
         
            +
                      VALUE prev_hsh_key = hsh_key;
         
     | 
| 
      
 321 
     | 
    
         
            +
                      hsh_key = ID2SYM(rb_intern2(pos + 1, k_pos - pos - 1));
         
     | 
| 
      
 322 
     | 
    
         
            +
             
     | 
| 
      
 323 
     | 
    
         
            +
                      if (hsh != Qnil) {
         
     | 
| 
      
 324 
     | 
    
         
            +
                        VALUE existing = rb_hash_aref(hsh, prev_hsh_key);
         
     | 
| 
      
 325 
     | 
    
         
            +
                        if (existing != Qnil) {
         
     | 
| 
      
 326 
     | 
    
         
            +
                          Check_Type(existing, T_HASH);
         
     | 
| 
      
 327 
     | 
    
         
            +
                          hsh = existing;
         
     | 
| 
      
 328 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 329 
     | 
    
         
            +
                          VALUE tmp = rb_hash_new();
         
     | 
| 
      
 330 
     | 
    
         
            +
                          rb_hash_aset(hsh, prev_hsh_key, tmp);
         
     | 
| 
      
 331 
     | 
    
         
            +
                          hsh = tmp;
         
     | 
| 
      
 332 
     | 
    
         
            +
                        }
         
     | 
| 
      
 333 
     | 
    
         
            +
                      } else if (arr != Qnil) {
         
     | 
| 
      
 334 
     | 
    
         
            +
                        VALUE nested_val = Qnil;
         
     | 
| 
      
 335 
     | 
    
         
            +
                        if (RARRAY_LEN(arr) != 0) {
         
     | 
| 
      
 336 
     | 
    
         
            +
                          VALUE tmp = rb_ary_entry(arr, -1);
         
     | 
| 
      
 337 
     | 
    
         
            +
                          Check_Type(tmp, T_HASH);
         
     | 
| 
      
 338 
     | 
    
         
            +
                          nested_val = rb_hash_aref(tmp, hsh_key);
         
     | 
| 
      
 339 
     | 
    
         
            +
                        }
         
     | 
| 
      
 340 
     | 
    
         
            +
             
     | 
| 
      
 341 
     | 
    
         
            +
                        // handle Rails' smart key grouping;
         
     | 
| 
      
 342 
     | 
    
         
            +
                        //   "users[][data][id]=11&users[][data][name]=ross&users[][data][id]=22&users[][data][name]=chandler"
         
     | 
| 
      
 343 
     | 
    
         
            +
                        // should result in:
         
     | 
| 
      
 344 
     | 
    
         
            +
                        //   { users: [{ data: { id: "11", name: "ross" } }, { data: { id: "22", name: "chandler" } }] }
         
     | 
| 
      
 345 
     | 
    
         
            +
                        if (RB_TYPE_P(nested_val, T_HASH)) {
         
     | 
| 
      
 346 
     | 
    
         
            +
                          char *n_pos_start = k_pos + 1, *n_pos_end = k_pos + 1;
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
                          while (nested_val != Qnil && *n_pos_start == '[' && *(n_pos_start + 1) != ']' && *n_pos_end != '&' && *n_pos_end != '=' && n_pos_end < end) {
         
     | 
| 
      
 349 
     | 
    
         
            +
                            n_pos_end++;
         
     | 
| 
      
 350 
     | 
    
         
            +
             
     | 
| 
      
 351 
     | 
    
         
            +
                            if (*n_pos_end == ']') {
         
     | 
| 
      
 352 
     | 
    
         
            +
                              VALUE nested_key = ID2SYM(rb_intern2(n_pos_start + 1, n_pos_end - n_pos_start - 1));
         
     | 
| 
      
 353 
     | 
    
         
            +
                              Check_Type(nested_val, T_HASH);
         
     | 
| 
      
 354 
     | 
    
         
            +
                              nested_val = rb_hash_aref(nested_val, nested_key);
         
     | 
| 
      
 355 
     | 
    
         
            +
                              n_pos_start = ++n_pos_end;
         
     | 
| 
      
 356 
     | 
    
         
            +
                            }
         
     | 
| 
      
 357 
     | 
    
         
            +
                          }
         
     | 
| 
      
 358 
     | 
    
         
            +
                        }
         
     | 
| 
      
 359 
     | 
    
         
            +
             
     | 
| 
      
 360 
     | 
    
         
            +
                        // use a new hash if there's none under this key or the existing one already has such key
         
     | 
| 
      
 361 
     | 
    
         
            +
                        if (RARRAY_LEN(arr) == 0 || nested_val != Qnil) {
         
     | 
| 
      
 362 
     | 
    
         
            +
                          hsh = rb_hash_new();
         
     | 
| 
      
 363 
     | 
    
         
            +
                          rb_ary_push(arr, hsh);
         
     | 
| 
      
 364 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 365 
     | 
    
         
            +
                          hsh = rb_ary_entry(arr, -1);
         
     | 
| 
      
 366 
     | 
    
         
            +
                          if (hsh != Qnil) {
         
     | 
| 
      
 367 
     | 
    
         
            +
                            Check_Type(hsh, T_HASH);
         
     | 
| 
      
 368 
     | 
    
         
            +
                          }
         
     | 
| 
      
 369 
     | 
    
         
            +
                        }
         
     | 
| 
      
 370 
     | 
    
         
            +
             
     | 
| 
      
 371 
     | 
    
         
            +
                        arr = Qnil;
         
     | 
| 
      
 372 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 373 
     | 
    
         
            +
                        VALUE tmp = rb_hash_aref(params, k);
         
     | 
| 
      
 374 
     | 
    
         
            +
                        if (tmp != Qnil) {
         
     | 
| 
      
 375 
     | 
    
         
            +
                          Check_Type(tmp, T_HASH);
         
     | 
| 
      
 376 
     | 
    
         
            +
                          hsh = tmp;
         
     | 
| 
      
 377 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 378 
     | 
    
         
            +
                          hsh = rb_hash_new();
         
     | 
| 
      
 379 
     | 
    
         
            +
                          rb_hash_aset(params, k, hsh);
         
     | 
| 
      
 380 
     | 
    
         
            +
                        }
         
     | 
| 
      
 381 
     | 
    
         
            +
                      }
         
     | 
| 
      
 382 
     | 
    
         
            +
             
     | 
| 
      
 383 
     | 
    
         
            +
                      pos = k_pos + 1;
         
     | 
| 
      
 384 
     | 
    
         
            +
             
     | 
| 
      
 385 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 386 
     | 
    
         
            +
                      pos++;
         
     | 
| 
      
 387 
     | 
    
         
            +
                    }
         
     | 
| 
      
 388 
     | 
    
         
            +
                  }
         
     | 
| 
      
 389 
     | 
    
         
            +
             
     | 
| 
      
 390 
     | 
    
         
            +
                  //
         
     | 
| 
      
 391 
     | 
    
         
            +
                  // write the final object into `params`
         
     | 
| 
      
 392 
     | 
    
         
            +
                  //
         
     | 
| 
      
 393 
     | 
    
         
            +
             
     | 
| 
      
 394 
     | 
    
         
            +
                  for (v_pos = pos + 1; *v_pos != '&' && v_pos < end; v_pos++) {
         
     | 
| 
      
 395 
     | 
    
         
            +
                    if (*v_pos == '%' || *v_pos == '+') {
         
     | 
| 
      
 396 
     | 
    
         
            +
                      should_decode = 1;
         
     | 
| 
      
 397 
     | 
    
         
            +
                    }
         
     | 
| 
      
 398 
     | 
    
         
            +
                  }
         
     | 
| 
      
 399 
     | 
    
         
            +
             
     | 
| 
      
 400 
     | 
    
         
            +
                  v = rb_str_new(pos + 1, v_pos - pos - 1);
         
     | 
| 
      
 401 
     | 
    
         
            +
                  if (should_decode) {
         
     | 
| 
      
 402 
     | 
    
         
            +
                    url_decode_inplace(Qnil, v);
         
     | 
| 
      
 403 
     | 
    
         
            +
                    should_decode = 0;
         
     | 
| 
      
 404 
     | 
    
         
            +
                  }
         
     | 
| 
      
 405 
     | 
    
         
            +
             
     | 
| 
      
 406 
     | 
    
         
            +
                  if (arr != Qnil) {
         
     | 
| 
      
 407 
     | 
    
         
            +
                    rb_ary_push(arr, v);
         
     | 
| 
      
 408 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 409 
     | 
    
         
            +
                    rb_hash_aset(hsh, hsh_key, v);
         
     | 
| 
      
 410 
     | 
    
         
            +
                  }
         
     | 
| 
      
 411 
     | 
    
         
            +
             
     | 
| 
      
 412 
     | 
    
         
            +
                  pos = k_pos = v_pos + 1;
         
     | 
| 
      
 413 
     | 
    
         
            +
             
     | 
| 
      
 414 
     | 
    
         
            +
                } else if (*k_pos == '&' || k_pos >= end) {
         
     | 
| 
      
 415 
     | 
    
         
            +
                  VALUE k = ID2SYM(rb_intern2(pos, k_pos - pos));
         
     | 
| 
      
 416 
     | 
    
         
            +
                  rb_hash_aset(params, k, Qnil);
         
     | 
| 
      
 417 
     | 
    
         
            +
                  pos = k_pos + 1;
         
     | 
| 
      
 418 
     | 
    
         
            +
                }
         
     | 
| 
      
 419 
     | 
    
         
            +
              }
         
     | 
| 
      
 420 
     | 
    
         
            +
             
     | 
| 
      
 421 
     | 
    
         
            +
              return params;
         
     | 
| 
      
 422 
     | 
    
         
            +
            }
         
     | 
| 
      
 423 
     | 
    
         
            +
             
     | 
| 
      
 424 
     | 
    
         
            +
            /**
         
     | 
| 
      
 425 
     | 
    
         
            +
            Convert query string into a Ruby object.
         
     | 
| 
      
 426 
     | 
    
         
            +
            */
         
     | 
| 
      
 427 
     | 
    
         
            +
            static VALUE parse_nested_query(VALUE self, VALUE r_str) {
         
     | 
| 
      
 428 
     | 
    
         
            +
              return parse_nested_query_internal(RSTRING_PTR(r_str), RSTRING_LEN(r_str));
         
     | 
| 
      
 429 
     | 
    
         
            +
              (void)self;
         
     | 
| 
      
 430 
     | 
    
         
            +
            }
         
     | 
| 
      
 431 
     | 
    
         
            +
             
     | 
| 
      
 432 
     | 
    
         
            +
            /**
         
     | 
| 
      
 433 
     | 
    
         
            +
            Convert urlencoded body into a Ruby object.
         
     | 
| 
      
 434 
     | 
    
         
            +
            */
         
     | 
| 
      
 435 
     | 
    
         
            +
            static VALUE parse_urlencoded_nested_query(VALUE self, VALUE r_str) {
         
     | 
| 
      
 436 
     | 
    
         
            +
              ssize_t len = http_decode_url(RSTRING_PTR(r_str), RSTRING_PTR(r_str), RSTRING_LEN(r_str));
         
     | 
| 
      
 437 
     | 
    
         
            +
              if (len < 0) {
         
     | 
| 
      
 438 
     | 
    
         
            +
                rb_raise(rb_eRuntimeError, "Invalid encoding");
         
     | 
| 
      
 439 
     | 
    
         
            +
              }
         
     | 
| 
      
 440 
     | 
    
         
            +
              
         
     | 
| 
      
 441 
     | 
    
         
            +
              return parse_nested_query_internal(RSTRING_PTR(r_str), len);
         
     | 
| 
      
 442 
     | 
    
         
            +
              (void)self;
         
     | 
| 
      
 443 
     | 
    
         
            +
            }
         
     | 
| 
      
 444 
     | 
    
         
            +
             
     | 
| 
      
 445 
     | 
    
         
            +
            /**
         
     | 
| 
      
 446 
     | 
    
         
            +
            Convert multipart/form-data into a Ruby object.
         
     | 
| 
      
 447 
     | 
    
         
            +
            */
         
     | 
| 
      
 448 
     | 
    
         
            +
            static VALUE parse_multipart(VALUE self, VALUE rack_io, VALUE content_type) {
         
     | 
| 
      
 449 
     | 
    
         
            +
              http_s *h = IodineRackIO.get_handle(rack_io);
         
     | 
| 
      
 450 
     | 
    
         
            +
             
     | 
| 
      
 451 
     | 
    
         
            +
              if (content_type == Qnil) {
         
     | 
| 
      
 452 
     | 
    
         
            +
                rb_raise(rb_eRuntimeError, "Incorrect content type for multipart request");
         
     | 
| 
      
 453 
     | 
    
         
            +
              }
         
     | 
| 
      
 454 
     | 
    
         
            +
             
     | 
| 
      
 455 
     | 
    
         
            +
              return http_parse_multipart(h, RSTRING_PTR(content_type), RSTRING_LEN(content_type));
         
     | 
| 
      
 456 
     | 
    
         
            +
              (void)self;
         
     | 
| 
      
 457 
     | 
    
         
            +
            }
         
     | 
| 
      
 458 
     | 
    
         
            +
             
     | 
| 
       212 
459 
     | 
    
         
             
            /* *****************************************************************************
         
     | 
| 
       213 
460 
     | 
    
         
             
            Ruby Initialization
         
     | 
| 
       214 
461 
     | 
    
         
             
            ***************************************************************************** */
         
     | 
| 
         @@ -261,6 +508,9 @@ Results: 
     | 
|
| 
       261 
508 
     | 
    
         
             
              rb_define_module_function(tmp, "time2str", date_str, -1);
         
     | 
| 
       262 
509 
     | 
    
         
             
              rb_define_module_function(tmp, "rfc2109", iodine_rfc2109, 1);
         
     | 
| 
       263 
510 
     | 
    
         
             
              rb_define_module_function(tmp, "rfc2822", iodine_rfc2822, 1);
         
     | 
| 
      
 511 
     | 
    
         
            +
              rb_define_module_function(tmp, "parse_nested_query", parse_nested_query, 1);
         
     | 
| 
      
 512 
     | 
    
         
            +
              rb_define_module_function(tmp, "parse_urlencoded_nested_query", parse_urlencoded_nested_query, 1);
         
     | 
| 
      
 513 
     | 
    
         
            +
              rb_define_module_function(tmp, "parse_multipart", parse_multipart, 2);
         
     | 
| 
       264 
514 
     | 
    
         | 
| 
       265 
515 
     | 
    
         
             
              /*
         
     | 
| 
       266 
516 
     | 
    
         
             
            The monkey-patched methods are in this module, allowing Iodine::Rack::Utils to
         
     | 
    
        data/ext/iodine/iodine_http.c
    CHANGED
    
    | 
         @@ -106,6 +106,7 @@ rack_declare(XSENDFILE_TYPE);        // for X-Sendfile support 
     | 
|
| 
       106 
106 
     | 
    
         
             
            rack_declare(XSENDFILE_TYPE_HEADER); // for X-Sendfile support
         
     | 
| 
       107 
107 
     | 
    
         
             
            rack_declare(CONTENT_LENGTH_HEADER); // for X-Sendfile support
         
     | 
| 
       108 
108 
     | 
    
         
             
            rack_declare(IODINE_REQUEST_ID);
         
     | 
| 
      
 109 
     | 
    
         
            +
            rack_declare(IODINE_HAS_BODY);
         
     | 
| 
       109 
110 
     | 
    
         | 
| 
       110 
111 
     | 
    
         
             
            /* used internally to handle requests */
         
     | 
| 
       111 
112 
     | 
    
         
             
            typedef struct {
         
     | 
| 
         @@ -341,6 +342,9 @@ static inline VALUE copy2env(iodine_http_request_handle_s *handle) { 
     | 
|
| 
       341 
342 
     | 
    
         
             
              tmp = fiobj_obj2cstr(h->path);
         
     | 
| 
       342 
343 
     | 
    
         
             
              rb_hash_aset(env, PATH_INFO,
         
     | 
| 
       343 
344 
     | 
    
         
             
                           rb_enc_str_new(tmp.data, tmp.len, IodineBinaryEncoding));
         
     | 
| 
      
 345 
     | 
    
         
            +
             
     | 
| 
      
 346 
     | 
    
         
            +
              rb_hash_aset(env, IODINE_HAS_BODY, (h->body) ? Qtrue : Qfalse);
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
       344 
348 
     | 
    
         
             
              if (h->query) {
         
     | 
| 
       345 
349 
     | 
    
         
             
                tmp = fiobj_obj2cstr(h->query);
         
     | 
| 
       346 
350 
     | 
    
         
             
                rb_hash_aset(env, QUERY_STRING,
         
     | 
| 
         @@ -976,6 +980,7 @@ static void initialize_env_template(void) { 
     | 
|
| 
       976 
980 
     | 
    
         
             
              rb_hash_aset(env_template_no_upgrade, SERVER_NAME, QUERY_STRING);
         
     | 
| 
       977 
981 
     | 
    
         
             
              rb_hash_aset(env_template_no_upgrade, SERVER_PROTOCOL, QUERY_STRING);
         
     | 
| 
       978 
982 
     | 
    
         
             
              rb_hash_aset(env_template_no_upgrade, IODINE_REQUEST_ID, QUERY_STRING);
         
     | 
| 
      
 983 
     | 
    
         
            +
              rb_hash_aset(env_template_no_upgrade, IODINE_HAS_BODY, QUERY_STRING);
         
     | 
| 
       979 
984 
     | 
    
         | 
| 
       980 
985 
     | 
    
         
             
              /* WebSocket upgrade support */
         
     | 
| 
       981 
986 
     | 
    
         
             
              env_template_websockets = rb_hash_dup(env_template_no_upgrade);
         
     | 
| 
         @@ -1235,6 +1240,7 @@ void iodine_init_http(void) { 
     | 
|
| 
       1235 
1240 
     | 
    
         
             
              rack_autoset(HTTP_HOST);
         
     | 
| 
       1236 
1241 
     | 
    
         | 
| 
       1237 
1242 
     | 
    
         
             
              rack_autoset(IODINE_REQUEST_ID);
         
     | 
| 
      
 1243 
     | 
    
         
            +
              rack_autoset(IODINE_HAS_BODY);
         
     | 
| 
       1238 
1244 
     | 
    
         | 
| 
       1239 
1245 
     | 
    
         
             
              rack_set(HTTP_SCHEME, "http");
         
     | 
| 
       1240 
1246 
     | 
    
         
             
              rack_set(HTTPS_SCHEME, "https");
         
     | 
    
        data/ext/iodine/iodine_rack_io.c
    CHANGED
    
    
    
        data/ext/iodine/iodine_rack_io.h
    CHANGED
    
    
    
        data/ext/iodine/scheduler.c
    CHANGED
    
    | 
         @@ -2,6 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
            #include "iodine_store.h"
         
     | 
| 
       3 
3 
     | 
    
         
             
            #include "ruby.h"
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
      
 5 
     | 
    
         
            +
            #include <errno.h>
         
     | 
| 
       5 
6 
     | 
    
         
             
            #include <stddef.h>
         
     | 
| 
       6 
7 
     | 
    
         
             
            #include <stdint.h>
         
     | 
| 
       7 
8 
     | 
    
         
             
            #include <stdio.h>
         
     | 
| 
         @@ -14,6 +15,7 @@ 
     | 
|
| 
       14 
15 
     | 
    
         
             
            static ID call_id;
         
     | 
| 
       15 
16 
     | 
    
         
             
            static uint8_t ATTACH_ON_READ_READY_CALLBACK;
         
     | 
| 
       16 
17 
     | 
    
         
             
            static uint8_t ATTACH_ON_WRITE_READY_CALLBACK;
         
     | 
| 
      
 18 
     | 
    
         
            +
            static VALUE timeout_args[1];
         
     | 
| 
       17 
19 
     | 
    
         | 
| 
       18 
20 
     | 
    
         
             
            /* *****************************************************************************
         
     | 
| 
       19 
21 
     | 
    
         
             
            Fiber Scheduler API
         
     | 
| 
         @@ -27,6 +29,7 @@ static void noop(intptr_t uuid, fio_protocol_s *protocol) { 
     | 
|
| 
       27 
29 
     | 
    
         
             
            typedef struct {
         
     | 
| 
       28 
30 
     | 
    
         
             
              fio_protocol_s p;
         
     | 
| 
       29 
31 
     | 
    
         
             
              VALUE block;
         
     | 
| 
      
 32 
     | 
    
         
            +
              uint8_t fulfilled;
         
     | 
| 
       30 
33 
     | 
    
         
             
            } scheduler_protocol_s;
         
     | 
| 
       31 
34 
     | 
    
         | 
| 
       32 
35 
     | 
    
         | 
| 
         @@ -42,10 +45,20 @@ static void iodine_scheduler_task_close(intptr_t uuid, fio_protocol_s *fio_proto 
     | 
|
| 
       42 
45 
     | 
    
         
             
            static void iodine_scheduler_task_perform(intptr_t uuid, fio_protocol_s *fio_protocol) {
         
     | 
| 
       43 
46 
     | 
    
         
             
              scheduler_protocol_s *protocol = (scheduler_protocol_s *)fio_protocol;
         
     | 
| 
       44 
47 
     | 
    
         
             
              IodineCaller.call(protocol->block, call_id);
         
     | 
| 
      
 48 
     | 
    
         
            +
              protocol->fulfilled = 1;
         
     | 
| 
       45 
49 
     | 
    
         | 
| 
       46 
50 
     | 
    
         
             
              (void)uuid;
         
     | 
| 
       47 
51 
     | 
    
         
             
            }
         
     | 
| 
       48 
52 
     | 
    
         | 
| 
      
 53 
     | 
    
         
            +
            static void iodine_scheduler_task_timeout(intptr_t uuid, fio_protocol_s *fio_protocol) {
         
     | 
| 
      
 54 
     | 
    
         
            +
              scheduler_protocol_s *protocol = (scheduler_protocol_s *)fio_protocol;
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              if (!protocol->fulfilled) {
         
     | 
| 
      
 57 
     | 
    
         
            +
                IodineCaller.call2(protocol->block, call_id, 1, timeout_args);
         
     | 
| 
      
 58 
     | 
    
         
            +
                fio_close(uuid);
         
     | 
| 
      
 59 
     | 
    
         
            +
              }
         
     | 
| 
      
 60 
     | 
    
         
            +
            }
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
       49 
62 
     | 
    
         
             
            static VALUE iodine_scheduler_attach(VALUE self, VALUE r_fd, VALUE r_waittype, VALUE r_timeout) {
         
     | 
| 
       50 
63 
     | 
    
         
             
              Check_Type(r_fd, T_FIXNUM);
         
     | 
| 
       51 
64 
     | 
    
         
             
              int fd = FIX2INT(r_fd);
         
     | 
| 
         @@ -69,7 +82,7 @@ static VALUE iodine_scheduler_attach(VALUE self, VALUE r_fd, VALUE r_waittype, V 
     | 
|
| 
       69 
82 
     | 
    
         
             
                    .p.on_data = iodine_scheduler_task_perform,
         
     | 
| 
       70 
83 
     | 
    
         
             
                    .p.on_ready = iodine_scheduler_task_perform,
         
     | 
| 
       71 
84 
     | 
    
         
             
                    .p.on_close = iodine_scheduler_task_close,
         
     | 
| 
       72 
     | 
    
         
            -
                    .p.ping =  
     | 
| 
      
 85 
     | 
    
         
            +
                    .p.ping = iodine_scheduler_task_timeout,
         
     | 
| 
       73 
86 
     | 
    
         
             
                    .block = block,
         
     | 
| 
       74 
87 
     | 
    
         
             
                };
         
     | 
| 
       75 
88 
     | 
    
         
             
              } else if (waittype & ATTACH_ON_READ_READY_CALLBACK) {
         
     | 
| 
         @@ -77,7 +90,7 @@ static VALUE iodine_scheduler_attach(VALUE self, VALUE r_fd, VALUE r_waittype, V 
     | 
|
| 
       77 
90 
     | 
    
         
             
                    .p.on_data = iodine_scheduler_task_perform,
         
     | 
| 
       78 
91 
     | 
    
         
             
                    .p.on_ready = noop,
         
     | 
| 
       79 
92 
     | 
    
         
             
                    .p.on_close = iodine_scheduler_task_close,
         
     | 
| 
       80 
     | 
    
         
            -
                    .p.ping =  
     | 
| 
      
 93 
     | 
    
         
            +
                    .p.ping = iodine_scheduler_task_timeout,
         
     | 
| 
       81 
94 
     | 
    
         
             
                    .block = block,
         
     | 
| 
       82 
95 
     | 
    
         
             
                };
         
     | 
| 
       83 
96 
     | 
    
         
             
              } else if (waittype & ATTACH_ON_WRITE_READY_CALLBACK) {
         
     | 
| 
         @@ -85,7 +98,7 @@ static VALUE iodine_scheduler_attach(VALUE self, VALUE r_fd, VALUE r_waittype, V 
     | 
|
| 
       85 
98 
     | 
    
         
             
                    .p.on_data = noop,
         
     | 
| 
       86 
99 
     | 
    
         
             
                    .p.on_ready = iodine_scheduler_task_perform,
         
     | 
| 
       87 
100 
     | 
    
         
             
                    .p.on_close = iodine_scheduler_task_close,
         
     | 
| 
       88 
     | 
    
         
            -
                    .p.ping =  
     | 
| 
      
 101 
     | 
    
         
            +
                    .p.ping = iodine_scheduler_task_timeout,
         
     | 
| 
       89 
102 
     | 
    
         
             
                    .block = block,
         
     | 
| 
       90 
103 
     | 
    
         
             
                };
         
     | 
| 
       91 
104 
     | 
    
         
             
              }
         
     | 
| 
         @@ -161,6 +174,7 @@ Scheduler initialization 
     | 
|
| 
       161 
174 
     | 
    
         | 
| 
       162 
175 
     | 
    
         
             
            void iodine_scheduler_initialize(void) {
         
     | 
| 
       163 
176 
     | 
    
         
             
              call_id = rb_intern2("call", 4);
         
     | 
| 
      
 177 
     | 
    
         
            +
              timeout_args[0] = UINT2NUM(ETIMEDOUT);
         
     | 
| 
       164 
178 
     | 
    
         | 
| 
       165 
179 
     | 
    
         
             
              VALUE SchedulerModule = rb_define_module_under(IodineModule, "Scheduler");
         
     | 
| 
       166 
180 
     | 
    
         | 
    
        data/iodine.gemspec
    CHANGED
    
    | 
         @@ -44,7 +44,4 @@ Gem::Specification.new do |spec| 
     | 
|
| 
       44 
44 
     | 
    
         
             
              spec.add_development_dependency 'rspec', '>=3.9.0', '< 4.0'
         
     | 
| 
       45 
45 
     | 
    
         
             
              spec.add_development_dependency 'spec', '>=5.3.0', '< 6.0'
         
     | 
| 
       46 
46 
     | 
    
         
             
              spec.add_development_dependency 'rake-compiler', '>= 1', '< 2.0'
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
              spec.post_install_message = "Thank you for installing Iodine #{Iodine::VERSION}.\n" +
         
     | 
| 
       49 
     | 
    
         
            -
                                          "Remember: if iodine supports your business, it's only fair to give value back (code contributions / donations)."
         
     | 
| 
       50 
47 
     | 
    
         
             
            end
         
     | 
    
        data/lib/iodine/version.rb
    CHANGED
    
    
    
        data/lib/iodine.rb
    CHANGED
    
    | 
         @@ -1,5 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'stringio' # Used internally as a default RackIO
         
     | 
| 
       2 
2 
     | 
    
         
             
            require 'socket'  # TCPSocket is used internally for Hijack support
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'tempfile' # Used to generate temporary files when parsing multipart/form-data
         
     | 
| 
       3 
4 
     | 
    
         
             
            # require 'openssl' # For SSL/TLS support using OpenSSL
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
       5 
6 
     | 
    
         
             
            require_relative './iodine/version'
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: rage-iodine
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 2.1.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Boaz Segev
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire:
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: exe
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2023- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2023-11-03 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: rake
         
     | 
| 
         @@ -252,9 +252,7 @@ licenses: 
     | 
|
| 
       252 
252 
     | 
    
         
             
            - MIT
         
     | 
| 
       253 
253 
     | 
    
         
             
            metadata:
         
     | 
| 
       254 
254 
     | 
    
         
             
              allowed_push_host: https://rubygems.org
         
     | 
| 
       255 
     | 
    
         
            -
            post_install_message: 
     | 
| 
       256 
     | 
    
         
            -
              Thank you for installing Iodine 1.8.0.
         
     | 
| 
       257 
     | 
    
         
            -
              Remember: if iodine supports your business, it's only fair to give value back (code contributions / donations).
         
     | 
| 
      
 255 
     | 
    
         
            +
            post_install_message:
         
     | 
| 
       258 
256 
     | 
    
         
             
            rdoc_options: []
         
     | 
| 
       259 
257 
     | 
    
         
             
            require_paths:
         
     | 
| 
       260 
258 
     | 
    
         
             
            - lib
         
     |