libcouchbase 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (561) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +35 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +24 -0
  8. data/README.md +389 -0
  9. data/Rakefile +75 -0
  10. data/ext/README.md +6 -0
  11. data/ext/Rakefile +20 -0
  12. data/ext/libcouchbase/.gitignore +130 -0
  13. data/ext/libcouchbase/.travis.yml +19 -0
  14. data/ext/libcouchbase/CMakeLists.txt +429 -0
  15. data/ext/libcouchbase/CONTRIBUTING.md +124 -0
  16. data/ext/libcouchbase/LICENSE +202 -0
  17. data/ext/libcouchbase/README.markdown +163 -0
  18. data/ext/libcouchbase/RELEASE_NOTES.markdown +2691 -0
  19. data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +27 -0
  20. data/ext/libcouchbase/cmake/Modules/CopyPDB.cmake +42 -0
  21. data/ext/libcouchbase/cmake/Modules/DistScript.cmake +17 -0
  22. data/ext/libcouchbase/cmake/Modules/DownloadLcbDep.cmake +20 -0
  23. data/ext/libcouchbase/cmake/Modules/FindCouchbaseHdrHistogram.cmake +15 -0
  24. data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibev.cmake +73 -0
  25. data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibevent.cmake +52 -0
  26. data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibuv.cmake +56 -0
  27. data/ext/libcouchbase/cmake/Modules/FindCouchbaseSnappy.cmake +11 -0
  28. data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +29 -0
  29. data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +133 -0
  30. data/ext/libcouchbase/cmake/Modules/GetPlatformCCInfo.cmake +45 -0
  31. data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +70 -0
  32. data/ext/libcouchbase/cmake/config-cmake.h.in +60 -0
  33. data/ext/libcouchbase/cmake/configure +357 -0
  34. data/ext/libcouchbase/cmake/defs.mk.in +8 -0
  35. data/ext/libcouchbase/cmake/dtrace-instr-link.pl +38 -0
  36. data/ext/libcouchbase/cmake/source_files.cmake +73 -0
  37. data/ext/libcouchbase/configure.pl +1 -0
  38. data/ext/libcouchbase/contrib/cJSON/cJSON.c +624 -0
  39. data/ext/libcouchbase/contrib/cJSON/cJSON.h +158 -0
  40. data/ext/libcouchbase/contrib/cbsasl/CMakeLists.txt +9 -0
  41. data/ext/libcouchbase/contrib/cbsasl/COPYING +202 -0
  42. data/ext/libcouchbase/contrib/cbsasl/include/cbsasl/cbsasl.h +217 -0
  43. data/ext/libcouchbase/contrib/cbsasl/src/client.c +205 -0
  44. data/ext/libcouchbase/contrib/cbsasl/src/common.c +46 -0
  45. data/ext/libcouchbase/contrib/cbsasl/src/cram-md5/hmac.c +67 -0
  46. data/ext/libcouchbase/contrib/cbsasl/src/cram-md5/hmac.h +33 -0
  47. data/ext/libcouchbase/contrib/cbsasl/src/cram-md5/md5.c +296 -0
  48. data/ext/libcouchbase/contrib/cbsasl/src/cram-md5/md5.h +45 -0
  49. data/ext/libcouchbase/contrib/cbsasl/src/hash.c +573 -0
  50. data/ext/libcouchbase/contrib/cbsasl/src/hash.h +15 -0
  51. data/ext/libcouchbase/contrib/cbsasl/src/util.h +31 -0
  52. data/ext/libcouchbase/contrib/cliopts/CMakeLists.txt +2 -0
  53. data/ext/libcouchbase/contrib/cliopts/cliopts.c +747 -0
  54. data/ext/libcouchbase/contrib/cliopts/cliopts.h +493 -0
  55. data/ext/libcouchbase/contrib/genhash/genhash.c +372 -0
  56. data/ext/libcouchbase/contrib/genhash/genhash.h +235 -0
  57. data/ext/libcouchbase/contrib/gtest-1.7.0/CHANGES +157 -0
  58. data/ext/libcouchbase/contrib/gtest-1.7.0/CMakeLists.txt +252 -0
  59. data/ext/libcouchbase/contrib/gtest-1.7.0/CONTRIBUTORS +37 -0
  60. data/ext/libcouchbase/contrib/gtest-1.7.0/LICENSE +28 -0
  61. data/ext/libcouchbase/contrib/gtest-1.7.0/MINIFY.sh +15 -0
  62. data/ext/libcouchbase/contrib/gtest-1.7.0/README +435 -0
  63. data/ext/libcouchbase/contrib/gtest-1.7.0/cmake/internal_utils.cmake +227 -0
  64. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/gtest-death-test.h +294 -0
  65. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/gtest-message.h +250 -0
  66. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/gtest-param-test.h +1421 -0
  67. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/gtest-param-test.h.pump +487 -0
  68. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/gtest-printers.h +855 -0
  69. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/gtest-spi.h +232 -0
  70. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/gtest-test-part.h +179 -0
  71. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/gtest-typed-test.h +259 -0
  72. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/gtest.h +2291 -0
  73. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/gtest_pred_impl.h +358 -0
  74. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/gtest_prod.h +58 -0
  75. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-death-test-internal.h +319 -0
  76. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-filepath.h +206 -0
  77. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-internal.h +1158 -0
  78. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-linked_ptr.h +233 -0
  79. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h +5143 -0
  80. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h.pump +301 -0
  81. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-param-util.h +619 -0
  82. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-port.h +1947 -0
  83. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-string.h +167 -0
  84. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-tuple.h +1012 -0
  85. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-tuple.h.pump +339 -0
  86. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-type-util.h +3331 -0
  87. data/ext/libcouchbase/contrib/gtest-1.7.0/include/gtest/internal/gtest-type-util.h.pump +297 -0
  88. data/ext/libcouchbase/contrib/gtest-1.7.0/src/gtest-all.cc +48 -0
  89. data/ext/libcouchbase/contrib/gtest-1.7.0/src/gtest-death-test.cc +1344 -0
  90. data/ext/libcouchbase/contrib/gtest-1.7.0/src/gtest-filepath.cc +382 -0
  91. data/ext/libcouchbase/contrib/gtest-1.7.0/src/gtest-internal-inl.h +1218 -0
  92. data/ext/libcouchbase/contrib/gtest-1.7.0/src/gtest-port.cc +805 -0
  93. data/ext/libcouchbase/contrib/gtest-1.7.0/src/gtest-printers.cc +363 -0
  94. data/ext/libcouchbase/contrib/gtest-1.7.0/src/gtest-test-part.cc +110 -0
  95. data/ext/libcouchbase/contrib/gtest-1.7.0/src/gtest-typed-test.cc +110 -0
  96. data/ext/libcouchbase/contrib/gtest-1.7.0/src/gtest.cc +5015 -0
  97. data/ext/libcouchbase/contrib/gtest-1.7.0/src/gtest_main.cc +38 -0
  98. data/ext/libcouchbase/contrib/http_parser/LICENSE-MIT +23 -0
  99. data/ext/libcouchbase/contrib/http_parser/README.md +178 -0
  100. data/ext/libcouchbase/contrib/http_parser/http_parser.c +2060 -0
  101. data/ext/libcouchbase/contrib/http_parser/http_parser.h +321 -0
  102. data/ext/libcouchbase/contrib/jsonsl/LICENSE +20 -0
  103. data/ext/libcouchbase/contrib/jsonsl/jsonsl.c +1452 -0
  104. data/ext/libcouchbase/contrib/jsonsl/jsonsl.h +971 -0
  105. data/ext/libcouchbase/contrib/lcb-jsoncpp/CMakeLists.txt +6 -0
  106. data/ext/libcouchbase/contrib/lcb-jsoncpp/LICENSE +55 -0
  107. data/ext/libcouchbase/contrib/lcb-jsoncpp/lcb-jsoncpp-forwards.h +255 -0
  108. data/ext/libcouchbase/contrib/lcb-jsoncpp/lcb-jsoncpp.cpp +4892 -0
  109. data/ext/libcouchbase/contrib/lcb-jsoncpp/lcb-jsoncpp.h +1961 -0
  110. data/ext/libcouchbase/contrib/snappy/CMakeLists.txt +8 -0
  111. data/ext/libcouchbase/contrib/snappy/COPYING +28 -0
  112. data/ext/libcouchbase/contrib/snappy/snappy-c.cc +90 -0
  113. data/ext/libcouchbase/contrib/snappy/snappy-c.h +138 -0
  114. data/ext/libcouchbase/contrib/snappy/snappy-internal.h +150 -0
  115. data/ext/libcouchbase/contrib/snappy/snappy-lcb-msvc.h +5 -0
  116. data/ext/libcouchbase/contrib/snappy/snappy-sinksource.cc +71 -0
  117. data/ext/libcouchbase/contrib/snappy/snappy-sinksource.h +137 -0
  118. data/ext/libcouchbase/contrib/snappy/snappy-stubs-internal.cc +42 -0
  119. data/ext/libcouchbase/contrib/snappy/snappy-stubs-internal.h +491 -0
  120. data/ext/libcouchbase/contrib/snappy/snappy-stubs-public.h +98 -0
  121. data/ext/libcouchbase/contrib/snappy/snappy.cc +1307 -0
  122. data/ext/libcouchbase/contrib/snappy/snappy.h +184 -0
  123. data/ext/libcouchbase/contrib/win32-defs/iocpdefs.h +133 -0
  124. data/ext/libcouchbase/contrib/win32-defs/mingwdefs.h +4396 -0
  125. data/ext/libcouchbase/contrib/win32-defs/win_stdint.h +258 -0
  126. data/ext/libcouchbase/example/CMakeLists.txt +37 -0
  127. data/ext/libcouchbase/example/README.markdown +47 -0
  128. data/ext/libcouchbase/example/db/db.c +167 -0
  129. data/ext/libcouchbase/example/db/vb.c +227 -0
  130. data/ext/libcouchbase/example/instancepool/main.cc +102 -0
  131. data/ext/libcouchbase/example/instancepool/pool.cc +102 -0
  132. data/ext/libcouchbase/example/instancepool/pool.h +69 -0
  133. data/ext/libcouchbase/example/libeventdirect/main.c +148 -0
  134. data/ext/libcouchbase/example/mcc/mcc.cc +246 -0
  135. data/ext/libcouchbase/example/minimal/minimal.c +130 -0
  136. data/ext/libcouchbase/example/observe/observe.c +146 -0
  137. data/ext/libcouchbase/example/subdoc/subdoc-multi.cc +132 -0
  138. data/ext/libcouchbase/example/subdoc/subdoc-simple.cc +191 -0
  139. data/ext/libcouchbase/example/tick/tick.c +119 -0
  140. data/ext/libcouchbase/example/views/views-example.cc +83 -0
  141. data/ext/libcouchbase/include/libcouchbase/_cxxwrap.h +150 -0
  142. data/ext/libcouchbase/include/libcouchbase/api-legacy.h +1689 -0
  143. data/ext/libcouchbase/include/libcouchbase/api3.h +2 -0
  144. data/ext/libcouchbase/include/libcouchbase/assert.h +44 -0
  145. data/ext/libcouchbase/include/libcouchbase/cbft.h +109 -0
  146. data/ext/libcouchbase/include/libcouchbase/cntl-private.h +356 -0
  147. data/ext/libcouchbase/include/libcouchbase/cntl.h +937 -0
  148. data/ext/libcouchbase/include/libcouchbase/configuration.h.in +23 -0
  149. data/ext/libcouchbase/include/libcouchbase/couchbase.h +3677 -0
  150. data/ext/libcouchbase/include/libcouchbase/deprecated.h +300 -0
  151. data/ext/libcouchbase/include/libcouchbase/error.h +595 -0
  152. data/ext/libcouchbase/include/libcouchbase/http.h +1 -0
  153. data/ext/libcouchbase/include/libcouchbase/iops.h +1050 -0
  154. data/ext/libcouchbase/include/libcouchbase/ixmgmt.h +263 -0
  155. data/ext/libcouchbase/include/libcouchbase/kvbuf.h +132 -0
  156. data/ext/libcouchbase/include/libcouchbase/n1ql.h +364 -0
  157. data/ext/libcouchbase/include/libcouchbase/pktfwd.h +270 -0
  158. data/ext/libcouchbase/include/libcouchbase/plugins/io/bsdio-inl.c +367 -0
  159. data/ext/libcouchbase/include/libcouchbase/plugins/io/wsaerr-inl.c +76 -0
  160. data/ext/libcouchbase/include/libcouchbase/plugins/io/wsaerr.h +199 -0
  161. data/ext/libcouchbase/include/libcouchbase/subdoc.h +312 -0
  162. data/ext/libcouchbase/include/libcouchbase/sysdefs.h +98 -0
  163. data/ext/libcouchbase/include/libcouchbase/vbucket.h +643 -0
  164. data/ext/libcouchbase/include/libcouchbase/views.h +298 -0
  165. data/ext/libcouchbase/include/libcouchbase/visibility.h +65 -0
  166. data/ext/libcouchbase/include/memcached/COPYING +30 -0
  167. data/ext/libcouchbase/include/memcached/README +10 -0
  168. data/ext/libcouchbase/include/memcached/protocol_binary.h +1916 -0
  169. data/ext/libcouchbase/include/memcached/vbucket.h +42 -0
  170. data/ext/libcouchbase/packaging/README +7 -0
  171. data/ext/libcouchbase/packaging/abicheck/.gitignore +4 -0
  172. data/ext/libcouchbase/packaging/abicheck/Makefile +17 -0
  173. data/ext/libcouchbase/packaging/abicheck/README.md +27 -0
  174. data/ext/libcouchbase/packaging/abicheck/template.xml +3 -0
  175. data/ext/libcouchbase/packaging/deb/compat +1 -0
  176. data/ext/libcouchbase/packaging/deb/control +73 -0
  177. data/ext/libcouchbase/packaging/deb/copyright +10 -0
  178. data/ext/libcouchbase/packaging/deb/libcouchbase-dev.docs +3 -0
  179. data/ext/libcouchbase/packaging/deb/package.mk +31 -0
  180. data/ext/libcouchbase/packaging/deb/rules +46 -0
  181. data/ext/libcouchbase/packaging/deb/source/format +1 -0
  182. data/ext/libcouchbase/packaging/distinfo/README +1 -0
  183. data/ext/libcouchbase/packaging/distinfo/distinfo.cmake.in +4 -0
  184. data/ext/libcouchbase/packaging/dllversion.rc.in +39 -0
  185. data/ext/libcouchbase/packaging/libcouchbase.pc.in +10 -0
  186. data/ext/libcouchbase/packaging/nuget/libcouchbase.autopkg +76 -0
  187. data/ext/libcouchbase/packaging/parse-git-describe.pl +166 -0
  188. data/ext/libcouchbase/packaging/rpm/libcouchbase.spec.in +108 -0
  189. data/ext/libcouchbase/packaging/rpm/package.mk +40 -0
  190. data/ext/libcouchbase/plugins/io/iocp/CMakeLists.txt +9 -0
  191. data/ext/libcouchbase/plugins/io/iocp/iocp_iops.c +466 -0
  192. data/ext/libcouchbase/plugins/io/iocp/iocp_iops.h +217 -0
  193. data/ext/libcouchbase/plugins/io/iocp/iocp_loop.c +295 -0
  194. data/ext/libcouchbase/plugins/io/iocp/iocp_timer.c +79 -0
  195. data/ext/libcouchbase/plugins/io/iocp/iocp_util.c +229 -0
  196. data/ext/libcouchbase/plugins/io/libev/CMakeLists.txt +29 -0
  197. data/ext/libcouchbase/plugins/io/libev/libev_io_opts.h +65 -0
  198. data/ext/libcouchbase/plugins/io/libev/plugin-libev.c +289 -0
  199. data/ext/libcouchbase/plugins/io/libevent/CMakeLists.txt +29 -0
  200. data/ext/libcouchbase/plugins/io/libevent/libevent_io_opts.h +67 -0
  201. data/ext/libcouchbase/plugins/io/libevent/plugin-libevent.c +292 -0
  202. data/ext/libcouchbase/plugins/io/libuv/CMakeLists.txt +42 -0
  203. data/ext/libcouchbase/plugins/io/libuv/libuv_compat.h +212 -0
  204. data/ext/libcouchbase/plugins/io/libuv/libuv_io_opts.h +118 -0
  205. data/ext/libcouchbase/plugins/io/libuv/plugin-internal.h +148 -0
  206. data/ext/libcouchbase/plugins/io/libuv/plugin-libuv.c +648 -0
  207. data/ext/libcouchbase/plugins/io/select/CMakeLists.txt +11 -0
  208. data/ext/libcouchbase/plugins/io/select/plugin-select.c +448 -0
  209. data/ext/libcouchbase/plugins/io/select/select_io_opts.h +39 -0
  210. data/ext/libcouchbase/src/README.md +103 -0
  211. data/ext/libcouchbase/src/aspend.h +106 -0
  212. data/ext/libcouchbase/src/auth.cc +74 -0
  213. data/ext/libcouchbase/src/auth.h +54 -0
  214. data/ext/libcouchbase/src/bootstrap.c +269 -0
  215. data/ext/libcouchbase/src/bootstrap.h +129 -0
  216. data/ext/libcouchbase/src/bucketconfig/bc_cccp.c +495 -0
  217. data/ext/libcouchbase/src/bucketconfig/bc_file.c +347 -0
  218. data/ext/libcouchbase/src/bucketconfig/bc_http.c +630 -0
  219. data/ext/libcouchbase/src/bucketconfig/bc_http.h +82 -0
  220. data/ext/libcouchbase/src/bucketconfig/bc_mcraw.c +150 -0
  221. data/ext/libcouchbase/src/bucketconfig/clconfig.h +681 -0
  222. data/ext/libcouchbase/src/bucketconfig/confmon.c +474 -0
  223. data/ext/libcouchbase/src/callbacks.c +378 -0
  224. data/ext/libcouchbase/src/cbft.cc +210 -0
  225. data/ext/libcouchbase/src/cntl.cc +847 -0
  226. data/ext/libcouchbase/src/config_static.h +159 -0
  227. data/ext/libcouchbase/src/connspec.cc +462 -0
  228. data/ext/libcouchbase/src/connspec.h +105 -0
  229. data/ext/libcouchbase/src/ctx-log-inl.h +27 -0
  230. data/ext/libcouchbase/src/dump.c +98 -0
  231. data/ext/libcouchbase/src/getconfig.c +100 -0
  232. data/ext/libcouchbase/src/gethrtime.c +109 -0
  233. data/ext/libcouchbase/src/handler.c +922 -0
  234. data/ext/libcouchbase/src/hashset.c +164 -0
  235. data/ext/libcouchbase/src/hashset.h +86 -0
  236. data/ext/libcouchbase/src/hashtable.c +75 -0
  237. data/ext/libcouchbase/src/hdr_timings.c +92 -0
  238. data/ext/libcouchbase/src/hostlist.cc +301 -0
  239. data/ext/libcouchbase/src/hostlist.h +171 -0
  240. data/ext/libcouchbase/src/http/http-priv.h +307 -0
  241. data/ext/libcouchbase/src/http/http.cc +633 -0
  242. data/ext/libcouchbase/src/http/http.h +34 -0
  243. data/ext/libcouchbase/src/http/http_io.cc +307 -0
  244. data/ext/libcouchbase/src/instance.cc +722 -0
  245. data/ext/libcouchbase/src/internal.h +244 -0
  246. data/ext/libcouchbase/src/iofactory.c +575 -0
  247. data/ext/libcouchbase/src/jsparse/parser.cc +519 -0
  248. data/ext/libcouchbase/src/jsparse/parser.h +173 -0
  249. data/ext/libcouchbase/src/lcbht/lcbht.c +282 -0
  250. data/ext/libcouchbase/src/lcbht/lcbht.h +199 -0
  251. data/ext/libcouchbase/src/lcbio/connect.c +557 -0
  252. data/ext/libcouchbase/src/lcbio/connect.h +364 -0
  253. data/ext/libcouchbase/src/lcbio/ctx.c +611 -0
  254. data/ext/libcouchbase/src/lcbio/ctx.h +405 -0
  255. data/ext/libcouchbase/src/lcbio/iotable.c +290 -0
  256. data/ext/libcouchbase/src/lcbio/iotable.h +84 -0
  257. data/ext/libcouchbase/src/lcbio/ioutils.c +350 -0
  258. data/ext/libcouchbase/src/lcbio/ioutils.h +203 -0
  259. data/ext/libcouchbase/src/lcbio/lcbio.h +51 -0
  260. data/ext/libcouchbase/src/lcbio/manager.c +584 -0
  261. data/ext/libcouchbase/src/lcbio/manager.h +156 -0
  262. data/ext/libcouchbase/src/lcbio/protoctx.c +84 -0
  263. data/ext/libcouchbase/src/lcbio/rw-inl.h +115 -0
  264. data/ext/libcouchbase/src/lcbio/ssl.h +149 -0
  265. data/ext/libcouchbase/src/lcbio/timer-ng.h +179 -0
  266. data/ext/libcouchbase/src/lcbio/timer.c +132 -0
  267. data/ext/libcouchbase/src/legacy.c +430 -0
  268. data/ext/libcouchbase/src/list.c +144 -0
  269. data/ext/libcouchbase/src/list.h +127 -0
  270. data/ext/libcouchbase/src/logging.c +244 -0
  271. data/ext/libcouchbase/src/logging.h +86 -0
  272. data/ext/libcouchbase/src/mc/compress.c +90 -0
  273. data/ext/libcouchbase/src/mc/compress.h +61 -0
  274. data/ext/libcouchbase/src/mc/forward.c +186 -0
  275. data/ext/libcouchbase/src/mc/forward.h +90 -0
  276. data/ext/libcouchbase/src/mc/iovcursor-inl.h +279 -0
  277. data/ext/libcouchbase/src/mc/iovcursor.h +66 -0
  278. data/ext/libcouchbase/src/mc/mcreq-flush-inl.h +111 -0
  279. data/ext/libcouchbase/src/mc/mcreq.c +954 -0
  280. data/ext/libcouchbase/src/mc/mcreq.h +977 -0
  281. data/ext/libcouchbase/src/mcserver/mcserver.c +784 -0
  282. data/ext/libcouchbase/src/mcserver/mcserver.h +121 -0
  283. data/ext/libcouchbase/src/mcserver/negotiate.c +656 -0
  284. data/ext/libcouchbase/src/mcserver/negotiate.h +119 -0
  285. data/ext/libcouchbase/src/n1ql/ixmgmt.cc +860 -0
  286. data/ext/libcouchbase/src/n1ql/n1ql-internal.h +22 -0
  287. data/ext/libcouchbase/src/n1ql/n1ql.cc +729 -0
  288. data/ext/libcouchbase/src/n1ql/params.cc +215 -0
  289. data/ext/libcouchbase/src/netbuf/netbuf-defs.h +89 -0
  290. data/ext/libcouchbase/src/netbuf/netbuf-mblock.h +235 -0
  291. data/ext/libcouchbase/src/netbuf/netbuf.c +929 -0
  292. data/ext/libcouchbase/src/netbuf/netbuf.h +452 -0
  293. data/ext/libcouchbase/src/newconfig.c +385 -0
  294. data/ext/libcouchbase/src/nodeinfo.cc +194 -0
  295. data/ext/libcouchbase/src/operations/cbflush.c +71 -0
  296. data/ext/libcouchbase/src/operations/counter.c +116 -0
  297. data/ext/libcouchbase/src/operations/durability-cas.c +224 -0
  298. data/ext/libcouchbase/src/operations/durability-seqno.c +157 -0
  299. data/ext/libcouchbase/src/operations/durability.c +668 -0
  300. data/ext/libcouchbase/src/operations/durability_internal.h +199 -0
  301. data/ext/libcouchbase/src/operations/get.c +409 -0
  302. data/ext/libcouchbase/src/operations/observe-seqno.c +96 -0
  303. data/ext/libcouchbase/src/operations/observe.c +340 -0
  304. data/ext/libcouchbase/src/operations/pktfwd.c +86 -0
  305. data/ext/libcouchbase/src/operations/remove.c +83 -0
  306. data/ext/libcouchbase/src/operations/stats.c +461 -0
  307. data/ext/libcouchbase/src/operations/store.c +360 -0
  308. data/ext/libcouchbase/src/operations/subdoc.cc +510 -0
  309. data/ext/libcouchbase/src/operations/touch.c +81 -0
  310. data/ext/libcouchbase/src/packetutils.c +60 -0
  311. data/ext/libcouchbase/src/packetutils.h +147 -0
  312. data/ext/libcouchbase/src/probes.d +211 -0
  313. data/ext/libcouchbase/src/rdb/bigalloc.c +225 -0
  314. data/ext/libcouchbase/src/rdb/bigalloc.h +73 -0
  315. data/ext/libcouchbase/src/rdb/chunkalloc.c +174 -0
  316. data/ext/libcouchbase/src/rdb/libcalloc.c +94 -0
  317. data/ext/libcouchbase/src/rdb/rope.c +419 -0
  318. data/ext/libcouchbase/src/rdb/rope.h +488 -0
  319. data/ext/libcouchbase/src/retrychk.c +113 -0
  320. data/ext/libcouchbase/src/retryq.c +424 -0
  321. data/ext/libcouchbase/src/retryq.h +157 -0
  322. data/ext/libcouchbase/src/ringbuffer.c +442 -0
  323. data/ext/libcouchbase/src/ringbuffer.h +100 -0
  324. data/ext/libcouchbase/src/settings.c +95 -0
  325. data/ext/libcouchbase/src/settings.h +188 -0
  326. data/ext/libcouchbase/src/simplestring.c +211 -0
  327. data/ext/libcouchbase/src/simplestring.h +228 -0
  328. data/ext/libcouchbase/src/sllist-inl.h +197 -0
  329. data/ext/libcouchbase/src/sllist.h +76 -0
  330. data/ext/libcouchbase/src/ssl/CMakeLists.txt +23 -0
  331. data/ext/libcouchbase/src/ssl/ssl_c.c +415 -0
  332. data/ext/libcouchbase/src/ssl/ssl_common.c +454 -0
  333. data/ext/libcouchbase/src/ssl/ssl_e.c +408 -0
  334. data/ext/libcouchbase/src/ssl/ssl_iot_common.h +180 -0
  335. data/ext/libcouchbase/src/ssobuf.h +82 -0
  336. data/ext/libcouchbase/src/strcodecs/base64.c +123 -0
  337. data/ext/libcouchbase/src/strcodecs/strcodecs.h +285 -0
  338. data/ext/libcouchbase/src/timings.c +208 -0
  339. data/ext/libcouchbase/src/trace.h +105 -0
  340. data/ext/libcouchbase/src/utilities.c +171 -0
  341. data/ext/libcouchbase/src/vbucket/CMakeLists.txt +2 -0
  342. data/ext/libcouchbase/src/vbucket/aliases.h +35 -0
  343. data/ext/libcouchbase/src/vbucket/crc32.h +83 -0
  344. data/ext/libcouchbase/src/vbucket/hash.h +30 -0
  345. data/ext/libcouchbase/src/vbucket/json-inl.h +112 -0
  346. data/ext/libcouchbase/src/vbucket/ketama.c +66 -0
  347. data/ext/libcouchbase/src/vbucket/rfc1321/global.h +32 -0
  348. data/ext/libcouchbase/src/vbucket/rfc1321/md5.h +35 -0
  349. data/ext/libcouchbase/src/vbucket/rfc1321/md5c-inl.h +335 -0
  350. data/ext/libcouchbase/src/vbucket/vbucket.c +1543 -0
  351. data/ext/libcouchbase/src/views/docreq.c +194 -0
  352. data/ext/libcouchbase/src/views/docreq.h +83 -0
  353. data/ext/libcouchbase/src/views/viewreq.c +358 -0
  354. data/ext/libcouchbase/src/views/viewreq.h +36 -0
  355. data/ext/libcouchbase/src/wait.c +161 -0
  356. data/ext/libcouchbase/tests/CMakeLists.txt +140 -0
  357. data/ext/libcouchbase/tests/basic/t_base64.cc +81 -0
  358. data/ext/libcouchbase/tests/basic/t_ccbc103.cc +95 -0
  359. data/ext/libcouchbase/tests/basic/t_connstr.cc +404 -0
  360. data/ext/libcouchbase/tests/basic/t_creds.cc +32 -0
  361. data/ext/libcouchbase/tests/basic/t_ctlcodes.cc +92 -0
  362. data/ext/libcouchbase/tests/basic/t_hashset.cc +262 -0
  363. data/ext/libcouchbase/tests/basic/t_host.cc +198 -0
  364. data/ext/libcouchbase/tests/basic/t_jsparse.cc +137 -0
  365. data/ext/libcouchbase/tests/basic/t_jsparse.h +589 -0
  366. data/ext/libcouchbase/tests/basic/t_list.cc +155 -0
  367. data/ext/libcouchbase/tests/basic/t_logger.cc +65 -0
  368. data/ext/libcouchbase/tests/basic/t_misc.cc +24 -0
  369. data/ext/libcouchbase/tests/basic/t_n1qlstrings.cc +18 -0
  370. data/ext/libcouchbase/tests/basic/t_netbuf.cc +446 -0
  371. data/ext/libcouchbase/tests/basic/t_packet.cc +222 -0
  372. data/ext/libcouchbase/tests/basic/t_ringbuffer.cc +278 -0
  373. data/ext/libcouchbase/tests/basic/t_slist.cc +429 -0
  374. data/ext/libcouchbase/tests/basic/t_strerror.cc +64 -0
  375. data/ext/libcouchbase/tests/basic/t_string.cc +112 -0
  376. data/ext/libcouchbase/tests/basic/t_urlencode.cc +132 -0
  377. data/ext/libcouchbase/tests/check-all.cc +608 -0
  378. data/ext/libcouchbase/tests/htparse/t_basic.cc +193 -0
  379. data/ext/libcouchbase/tests/ioserver/connection.cc +166 -0
  380. data/ext/libcouchbase/tests/ioserver/future.cc +50 -0
  381. data/ext/libcouchbase/tests/ioserver/ioserver.cc +104 -0
  382. data/ext/libcouchbase/tests/ioserver/ioserver.h +478 -0
  383. data/ext/libcouchbase/tests/ioserver/socket.cc +88 -0
  384. data/ext/libcouchbase/tests/ioserver/ssl_connection.cc +145 -0
  385. data/ext/libcouchbase/tests/ioserver/threads-pthreads.cc +119 -0
  386. data/ext/libcouchbase/tests/ioserver/threads-win32.cc +117 -0
  387. data/ext/libcouchbase/tests/ioserver/threads.h +66 -0
  388. data/ext/libcouchbase/tests/iotests/iotests.h +15 -0
  389. data/ext/libcouchbase/tests/iotests/mock-environment.cc +524 -0
  390. data/ext/libcouchbase/tests/iotests/mock-environment.h +385 -0
  391. data/ext/libcouchbase/tests/iotests/mock-unit-test.cc +67 -0
  392. data/ext/libcouchbase/tests/iotests/mock-unit-test.h +61 -0
  393. data/ext/libcouchbase/tests/iotests/serverparams.h +76 -0
  394. data/ext/libcouchbase/tests/iotests/t_arithmetic.cc +143 -0
  395. data/ext/libcouchbase/tests/iotests/t_behavior.cc +226 -0
  396. data/ext/libcouchbase/tests/iotests/t_configcache.cc +117 -0
  397. data/ext/libcouchbase/tests/iotests/t_confmon.cc +241 -0
  398. data/ext/libcouchbase/tests/iotests/t_durability.cc +1059 -0
  399. data/ext/libcouchbase/tests/iotests/t_forward.cc +110 -0
  400. data/ext/libcouchbase/tests/iotests/t_get.cc +512 -0
  401. data/ext/libcouchbase/tests/iotests/t_http.cc +438 -0
  402. data/ext/libcouchbase/tests/iotests/t_iops.cc +175 -0
  403. data/ext/libcouchbase/tests/iotests/t_lock.cc +275 -0
  404. data/ext/libcouchbase/tests/iotests/t_misc.cc +713 -0
  405. data/ext/libcouchbase/tests/iotests/t_mutate.cc +609 -0
  406. data/ext/libcouchbase/tests/iotests/t_n1ql.cc +270 -0
  407. data/ext/libcouchbase/tests/iotests/t_netfail.cc +654 -0
  408. data/ext/libcouchbase/tests/iotests/t_obseqno.cc +157 -0
  409. data/ext/libcouchbase/tests/iotests/t_regression.cc +321 -0
  410. data/ext/libcouchbase/tests/iotests/t_sched.cc +88 -0
  411. data/ext/libcouchbase/tests/iotests/t_serverops.cc +230 -0
  412. data/ext/libcouchbase/tests/iotests/t_smoke.cc +528 -0
  413. data/ext/libcouchbase/tests/iotests/t_subdoc.cc +822 -0
  414. data/ext/libcouchbase/tests/iotests/t_syncmode.cc +64 -0
  415. data/ext/libcouchbase/tests/iotests/t_views.cc +405 -0
  416. data/ext/libcouchbase/tests/iotests/testutil.cc +250 -0
  417. data/ext/libcouchbase/tests/iotests/testutil.h +163 -0
  418. data/ext/libcouchbase/tests/mc/mctest.h +119 -0
  419. data/ext/libcouchbase/tests/mc/pktmaker.h +101 -0
  420. data/ext/libcouchbase/tests/mc/t_alloc.cc +269 -0
  421. data/ext/libcouchbase/tests/mc/t_context.cc +100 -0
  422. data/ext/libcouchbase/tests/mc/t_flush.cc +185 -0
  423. data/ext/libcouchbase/tests/mc/t_forward.cc +239 -0
  424. data/ext/libcouchbase/tests/mc/t_ioflush.cc +102 -0
  425. data/ext/libcouchbase/tests/mc/t_iovcursor.cc +173 -0
  426. data/ext/libcouchbase/tests/mocksupport/procutil.c +305 -0
  427. data/ext/libcouchbase/tests/mocksupport/procutil.h +89 -0
  428. data/ext/libcouchbase/tests/mocksupport/server.c +391 -0
  429. data/ext/libcouchbase/tests/mocksupport/server.h +72 -0
  430. data/ext/libcouchbase/tests/mocksupport/timeout.c +69 -0
  431. data/ext/libcouchbase/tests/nonio_tests.cc +23 -0
  432. data/ext/libcouchbase/tests/rdb/rdbtest.h +133 -0
  433. data/ext/libcouchbase/tests/rdb/t_basic.cc +128 -0
  434. data/ext/libcouchbase/tests/rdb/t_bigalloc.cc +93 -0
  435. data/ext/libcouchbase/tests/rdb/t_refs.cc +112 -0
  436. data/ext/libcouchbase/tests/socktests/socktest.cc +347 -0
  437. data/ext/libcouchbase/tests/socktests/socktest.h +448 -0
  438. data/ext/libcouchbase/tests/socktests/t_basic.cc +143 -0
  439. data/ext/libcouchbase/tests/socktests/t_ctx.cc +73 -0
  440. data/ext/libcouchbase/tests/socktests/t_manager.cc +179 -0
  441. data/ext/libcouchbase/tests/socktests/t_putex.cc +256 -0
  442. data/ext/libcouchbase/tests/socktests/t_read.cc +187 -0
  443. data/ext/libcouchbase/tests/socktests/t_reentrant.cc +143 -0
  444. data/ext/libcouchbase/tests/socktests/t_ssl.cc +80 -0
  445. data/ext/libcouchbase/tests/socktests/t_write.cc +95 -0
  446. data/ext/libcouchbase/tests/start_mock.bat +15 -0
  447. data/ext/libcouchbase/tests/start_mock.sh +42 -0
  448. data/ext/libcouchbase/tests/unit_tests.cc +43 -0
  449. data/ext/libcouchbase/tests/vbucket/confdata/bad.json +101 -0
  450. data/ext/libcouchbase/tests/vbucket/confdata/full_25.json +363 -0
  451. data/ext/libcouchbase/tests/vbucket/confdata/memd_25.json +90 -0
  452. data/ext/libcouchbase/tests/vbucket/confdata/memd_30.json +1 -0
  453. data/ext/libcouchbase/tests/vbucket/confdata/memd_45.json +1 -0
  454. data/ext/libcouchbase/tests/vbucket/confdata/terse_25.json +291 -0
  455. data/ext/libcouchbase/tests/vbucket/confdata/terse_30.json +1 -0
  456. data/ext/libcouchbase/tests/vbucket/t_config.cc +341 -0
  457. data/ext/libcouchbase/tools/CMakeLists.txt +51 -0
  458. data/ext/libcouchbase/tools/cbc-handlers.h +462 -0
  459. data/ext/libcouchbase/tools/cbc-n1qlback.cc +439 -0
  460. data/ext/libcouchbase/tools/cbc-pillowfight.cc +822 -0
  461. data/ext/libcouchbase/tools/cbc.cc +1541 -0
  462. data/ext/libcouchbase/tools/common/histogram.cc +43 -0
  463. data/ext/libcouchbase/tools/common/histogram.h +23 -0
  464. data/ext/libcouchbase/tools/common/my_inttypes.h +22 -0
  465. data/ext/libcouchbase/tools/common/options.cc +420 -0
  466. data/ext/libcouchbase/tools/common/options.h +81 -0
  467. data/ext/libcouchbase/tools/docgen/docgen.h +469 -0
  468. data/ext/libcouchbase/tools/docgen/loc.h +210 -0
  469. data/ext/libcouchbase/tools/docgen/placeholders.h +211 -0
  470. data/ext/libcouchbase/tools/docgen/seqgen.h +94 -0
  471. data/lib/libcouchbase.rb +36 -0
  472. data/lib/libcouchbase/bucket.rb +819 -0
  473. data/lib/libcouchbase/callbacks.rb +72 -0
  474. data/lib/libcouchbase/connection.rb +790 -0
  475. data/lib/libcouchbase/design_docs.rb +86 -0
  476. data/lib/libcouchbase/error.rb +68 -0
  477. data/lib/libcouchbase/ext/libcouchbase.rb +1135 -0
  478. data/lib/libcouchbase/ext/libcouchbase/cmdbase.rb +23 -0
  479. data/lib/libcouchbase/ext/libcouchbase/cmdcounter.rb +36 -0
  480. data/lib/libcouchbase/ext/libcouchbase/cmdendure.rb +26 -0
  481. data/lib/libcouchbase/ext/libcouchbase/cmdfts.rb +24 -0
  482. data/lib/libcouchbase/ext/libcouchbase/cmdget.rb +30 -0
  483. data/lib/libcouchbase/ext/libcouchbase/cmdgetreplica.rb +49 -0
  484. data/lib/libcouchbase/ext/libcouchbase/cmdhttp.rb +58 -0
  485. data/lib/libcouchbase/ext/libcouchbase/cmdn1ql.rb +40 -0
  486. data/lib/libcouchbase/ext/libcouchbase/cmdobseqno.rb +33 -0
  487. data/lib/libcouchbase/ext/libcouchbase/cmdobserve.rb +30 -0
  488. data/lib/libcouchbase/ext/libcouchbase/cmdstore.rb +40 -0
  489. data/lib/libcouchbase/ext/libcouchbase/cmdstoredur.rb +45 -0
  490. data/lib/libcouchbase/ext/libcouchbase/cmdsubdoc.rb +49 -0
  491. data/lib/libcouchbase/ext/libcouchbase/cmdverbosity.rb +29 -0
  492. data/lib/libcouchbase/ext/libcouchbase/cmdviewquery.rb +61 -0
  493. data/lib/libcouchbase/ext/libcouchbase/contigbuf.rb +14 -0
  494. data/lib/libcouchbase/ext/libcouchbase/create_st.rb +15 -0
  495. data/lib/libcouchbase/ext/libcouchbase/create_st0.rb +23 -0
  496. data/lib/libcouchbase/ext/libcouchbase/create_st1.rb +26 -0
  497. data/lib/libcouchbase/ext/libcouchbase/create_st2.rb +32 -0
  498. data/lib/libcouchbase/ext/libcouchbase/create_st3.rb +26 -0
  499. data/lib/libcouchbase/ext/libcouchbase/crst_u.rb +20 -0
  500. data/lib/libcouchbase/ext/libcouchbase/durability_opts_st_v.rb +11 -0
  501. data/lib/libcouchbase/ext/libcouchbase/durability_opts_t.rb +14 -0
  502. data/lib/libcouchbase/ext/libcouchbase/durabilityopt_sv0.rb +63 -0
  503. data/lib/libcouchbase/ext/libcouchbase/enums.rb +991 -0
  504. data/lib/libcouchbase/ext/libcouchbase/fragbuf.rb +18 -0
  505. data/lib/libcouchbase/ext/libcouchbase/ftshandle.rb +7 -0
  506. data/lib/libcouchbase/ext/libcouchbase/histogram.rb +34 -0
  507. data/lib/libcouchbase/ext/libcouchbase/http_request_t.rb +7 -0
  508. data/lib/libcouchbase/ext/libcouchbase/keybuf.rb +20 -0
  509. data/lib/libcouchbase/ext/libcouchbase/multicmd_ctx.rb +30 -0
  510. data/lib/libcouchbase/ext/libcouchbase/mutation_token.rb +17 -0
  511. data/lib/libcouchbase/ext/libcouchbase/n1qlhandle.rb +7 -0
  512. data/lib/libcouchbase/ext/libcouchbase/n1qlparams.rb +7 -0
  513. data/lib/libcouchbase/ext/libcouchbase/respbase.rb +29 -0
  514. data/lib/libcouchbase/ext/libcouchbase/respcounter.rb +32 -0
  515. data/lib/libcouchbase/ext/libcouchbase/respendure.rb +49 -0
  516. data/lib/libcouchbase/ext/libcouchbase/respfts.rb +40 -0
  517. data/lib/libcouchbase/ext/libcouchbase/respget.rb +44 -0
  518. data/lib/libcouchbase/ext/libcouchbase/resphttp.rb +48 -0
  519. data/lib/libcouchbase/ext/libcouchbase/respmcversion.rb +38 -0
  520. data/lib/libcouchbase/ext/libcouchbase/respn1ql.rb +41 -0
  521. data/lib/libcouchbase/ext/libcouchbase/respobseqno.rb +52 -0
  522. data/lib/libcouchbase/ext/libcouchbase/respobserve.rb +41 -0
  523. data/lib/libcouchbase/ext/libcouchbase/respserverbase.rb +32 -0
  524. data/lib/libcouchbase/ext/libcouchbase/respstats.rb +38 -0
  525. data/lib/libcouchbase/ext/libcouchbase/respstore.rb +32 -0
  526. data/lib/libcouchbase/ext/libcouchbase/respstoredur.rb +38 -0
  527. data/lib/libcouchbase/ext/libcouchbase/respsubdoc.rb +35 -0
  528. data/lib/libcouchbase/ext/libcouchbase/respviewquery.rb +67 -0
  529. data/lib/libcouchbase/ext/libcouchbase/sdentry.rb +22 -0
  530. data/lib/libcouchbase/ext/libcouchbase/sdspec.rb +26 -0
  531. data/lib/libcouchbase/ext/libcouchbase/t.rb +7 -0
  532. data/lib/libcouchbase/ext/libcouchbase/valbuf.rb +22 -0
  533. data/lib/libcouchbase/ext/libcouchbase/valbuf_u_buf.rb +14 -0
  534. data/lib/libcouchbase/ext/libcouchbase/viewhandle.rb +7 -0
  535. data/lib/libcouchbase/ext/libcouchbase_iocp.rb +26 -0
  536. data/lib/libcouchbase/ext/libcouchbase_libuv.rb +18 -0
  537. data/lib/libcouchbase/ext/tasks.rb +87 -0
  538. data/lib/libcouchbase/n1ql.rb +73 -0
  539. data/lib/libcouchbase/query_full_text.rb +147 -0
  540. data/lib/libcouchbase/query_n1ql.rb +121 -0
  541. data/lib/libcouchbase/query_view.rb +129 -0
  542. data/lib/libcouchbase/results_fiber.rb +262 -0
  543. data/lib/libcouchbase/results_native.rb +211 -0
  544. data/lib/libcouchbase/version.rb +5 -0
  545. data/libcouchbase.gemspec +61 -0
  546. data/spec/bucket_spec.rb +270 -0
  547. data/spec/connection_spec.rb +277 -0
  548. data/spec/design_docs_spec.rb +23 -0
  549. data/spec/error_spec.rb +26 -0
  550. data/spec/fts_spec.rb +129 -0
  551. data/spec/n1ql_spec.rb +201 -0
  552. data/spec/results_libuv_spec.rb +229 -0
  553. data/spec/results_native_spec.rb +259 -0
  554. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/design.json +1 -0
  555. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/data-0000.cbb +0 -0
  556. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/failover.json +1 -0
  557. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/meta.json +1 -0
  558. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/seqno.json +1 -0
  559. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/snapshot_markers.json +1 -0
  560. data/spec/view_spec.rb +195 -0
  561. metadata +775 -0
@@ -0,0 +1,38 @@
1
+ // Copyright 2006, Google Inc.
2
+ // All rights reserved.
3
+ //
4
+ // Redistribution and use in source and binary forms, with or without
5
+ // modification, are permitted provided that the following conditions are
6
+ // met:
7
+ //
8
+ // * Redistributions of source code must retain the above copyright
9
+ // notice, this list of conditions and the following disclaimer.
10
+ // * Redistributions in binary form must reproduce the above
11
+ // copyright notice, this list of conditions and the following disclaimer
12
+ // in the documentation and/or other materials provided with the
13
+ // distribution.
14
+ // * Neither the name of Google Inc. nor the names of its
15
+ // contributors may be used to endorse or promote products derived from
16
+ // this software without specific prior written permission.
17
+ //
18
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ #include <stdio.h>
31
+
32
+ #include "gtest/gtest.h"
33
+
34
+ GTEST_API_ int main(int argc, char **argv) {
35
+ printf("Running main() from gtest_main.cc\n");
36
+ testing::InitGoogleTest(&argc, argv);
37
+ return RUN_ALL_TESTS();
38
+ }
@@ -0,0 +1,23 @@
1
+ http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
2
+ Igor Sysoev.
3
+
4
+ Additional changes are licensed under the same terms as NGINX and
5
+ copyright Joyent, Inc. and other Node contributors. All rights reserved.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to
9
+ deal in the Software without restriction, including without limitation the
10
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11
+ sell copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23
+ IN THE SOFTWARE.
@@ -0,0 +1,178 @@
1
+ HTTP Parser
2
+ ===========
3
+
4
+ This is a parser for HTTP messages written in C. It parses both requests and
5
+ responses. The parser is designed to be used in performance HTTP
6
+ applications. It does not make any syscalls nor allocations, it does not
7
+ buffer data, it can be interrupted at anytime. Depending on your
8
+ architecture, it only requires about 40 bytes of data per message
9
+ stream (in a web server that is per connection).
10
+
11
+ Features:
12
+
13
+ * No dependencies
14
+ * Handles persistent streams (keep-alive).
15
+ * Decodes chunked encoding.
16
+ * Upgrade support
17
+ * Defends against buffer overflow attacks.
18
+
19
+ The parser extracts the following information from HTTP messages:
20
+
21
+ * Header fields and values
22
+ * Content-Length
23
+ * Request method
24
+ * Response status code
25
+ * Transfer-Encoding
26
+ * HTTP version
27
+ * Request URL
28
+ * Message body
29
+
30
+
31
+ Usage
32
+ -----
33
+
34
+ One `http_parser` object is used per TCP connection. Initialize the struct
35
+ using `http_parser_init()` and set the callbacks. That might look something
36
+ like this for a request parser:
37
+
38
+ http_parser_settings settings;
39
+ settings.on_path = my_path_callback;
40
+ settings.on_header_field = my_header_field_callback;
41
+ /* ... */
42
+
43
+ http_parser *parser = malloc(sizeof(http_parser));
44
+ http_parser_init(parser, HTTP_REQUEST);
45
+ parser->data = my_socket;
46
+
47
+ When data is received on the socket execute the parser and check for errors.
48
+
49
+ size_t len = 80*1024, nparsed;
50
+ char buf[len];
51
+ ssize_t recved;
52
+
53
+ recved = recv(fd, buf, len, 0);
54
+
55
+ if (recved < 0) {
56
+ /* Handle error. */
57
+ }
58
+
59
+ /* Start up / continue the parser.
60
+ * Note we pass recved==0 to signal that EOF has been recieved.
61
+ */
62
+ nparsed = http_parser_execute(parser, &settings, buf, recved);
63
+
64
+ if (parser->upgrade) {
65
+ /* handle new protocol */
66
+ } else if (nparsed != recved) {
67
+ /* Handle error. Usually just close the connection. */
68
+ }
69
+
70
+ HTTP needs to know where the end of the stream is. For example, sometimes
71
+ servers send responses without Content-Length and expect the client to
72
+ consume input (for the body) until EOF. To tell http_parser about EOF, give
73
+ `0` as the forth parameter to `http_parser_execute()`. Callbacks and errors
74
+ can still be encountered during an EOF, so one must still be prepared
75
+ to receive them.
76
+
77
+ Scalar valued message information such as `status_code`, `method`, and the
78
+ HTTP version are stored in the parser structure. This data is only
79
+ temporally stored in `http_parser` and gets reset on each new message. If
80
+ this information is needed later, copy it out of the structure during the
81
+ `headers_complete` callback.
82
+
83
+ The parser decodes the transfer-encoding for both requests and responses
84
+ transparently. That is, a chunked encoding is decoded before being sent to
85
+ the on_body callback.
86
+
87
+
88
+ The Special Problem of Upgrade
89
+ ------------------------------
90
+
91
+ HTTP supports upgrading the connection to a different protocol. An
92
+ increasingly common example of this is the Web Socket protocol which sends
93
+ a request like
94
+
95
+ GET /demo HTTP/1.1
96
+ Upgrade: WebSocket
97
+ Connection: Upgrade
98
+ Host: example.com
99
+ Origin: http://example.com
100
+ WebSocket-Protocol: sample
101
+
102
+ followed by non-HTTP data.
103
+
104
+ (See http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 for more
105
+ information the Web Socket protocol.)
106
+
107
+ To support this, the parser will treat this as a normal HTTP message without a
108
+ body. Issuing both on_headers_complete and on_message_complete callbacks. However
109
+ http_parser_execute() will stop parsing at the end of the headers and return.
110
+
111
+ The user is expected to check if `parser->upgrade` has been set to 1 after
112
+ `http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied
113
+ offset by the return value of `http_parser_execute()`.
114
+
115
+
116
+ Callbacks
117
+ ---------
118
+
119
+ During the `http_parser_execute()` call, the callbacks set in
120
+ `http_parser_settings` will be executed. The parser maintains state and
121
+ never looks behind, so buffering the data is not necessary. If you need to
122
+ save certain data for later usage, you can do that from the callbacks.
123
+
124
+ There are two types of callbacks:
125
+
126
+ * notification `typedef int (*http_cb) (http_parser*);`
127
+ Callbacks: on_message_begin, on_headers_complete, on_message_complete.
128
+ * data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);`
129
+ Callbacks: (requests only) on_uri,
130
+ (common) on_header_field, on_header_value, on_body;
131
+
132
+ Callbacks must return 0 on success. Returning a non-zero value indicates
133
+ error to the parser, making it exit immediately.
134
+
135
+ In case you parse HTTP message in chunks (i.e. `read()` request line
136
+ from socket, parse, read half headers, parse, etc) your data callbacks
137
+ may be called more than once. Http-parser guarantees that data pointer is only
138
+ valid for the lifetime of callback. You can also `read()` into a heap allocated
139
+ buffer to avoid copying memory around if this fits your application.
140
+
141
+ Reading headers may be a tricky task if you read/parse headers partially.
142
+ Basically, you need to remember whether last header callback was field or value
143
+ and apply following logic:
144
+
145
+ (on_header_field and on_header_value shortened to on_h_*)
146
+ ------------------------ ------------ --------------------------------------------
147
+ | State (prev. callback) | Callback | Description/action |
148
+ ------------------------ ------------ --------------------------------------------
149
+ | nothing (first call) | on_h_field | Allocate new buffer and copy callback data |
150
+ | | | into it |
151
+ ------------------------ ------------ --------------------------------------------
152
+ | value | on_h_field | New header started. |
153
+ | | | Copy current name,value buffers to headers |
154
+ | | | list and allocate new buffer for new name |
155
+ ------------------------ ------------ --------------------------------------------
156
+ | field | on_h_field | Previous name continues. Reallocate name |
157
+ | | | buffer and append callback data to it |
158
+ ------------------------ ------------ --------------------------------------------
159
+ | field | on_h_value | Value for current header started. Allocate |
160
+ | | | new buffer and copy callback data to it |
161
+ ------------------------ ------------ --------------------------------------------
162
+ | value | on_h_value | Value continues. Reallocate value buffer |
163
+ | | | and append callback data to it |
164
+ ------------------------ ------------ --------------------------------------------
165
+
166
+
167
+ Parsing URLs
168
+ ------------
169
+
170
+ A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`.
171
+ Users of this library may wish to use it to parse URLs constructed from
172
+ consecutive `on_url` callbacks.
173
+
174
+ See examples of reading in headers:
175
+
176
+ * [partial example](http://gist.github.com/155877) in C
177
+ * [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C
178
+ * [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript
@@ -0,0 +1,2060 @@
1
+ /* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
2
+ *
3
+ * Additional changes are licensed under the same terms as NGINX and
4
+ * copyright Joyent, Inc. and other Node contributors. All rights reserved.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to
8
+ * deal in the Software without restriction, including without limitation the
9
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
+ * sell copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
+ * IN THE SOFTWARE.
23
+ */
24
+ #include "http_parser.h"
25
+ #include <assert.h>
26
+ #include <stddef.h>
27
+ #include <ctype.h>
28
+ #include <stdlib.h>
29
+ #include <string.h>
30
+ #include <limits.h>
31
+
32
+ #if defined(ULLONG_MAX) && __STDC_VERSION__ >= 199901L
33
+ # define HTTP_PARSER_ULLONG_MAX ULLONG_MAX
34
+ #else
35
+ # define HTTP_PARSER_ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
36
+ #endif
37
+
38
+ #ifndef MIN
39
+ # define MIN(a,b) ((a) < (b) ? (a) : (b))
40
+ #endif
41
+
42
+
43
+ #if HTTP_PARSER_DEBUG
44
+ #define SET_ERRNO(e) \
45
+ do { \
46
+ parser->http_errno = (e); \
47
+ parser->error_lineno = __LINE__; \
48
+ } while (0)
49
+ #else
50
+ #define SET_ERRNO(e) \
51
+ do { \
52
+ parser->http_errno = (e); \
53
+ } while(0)
54
+ #endif
55
+
56
+
57
+ /* Run the notify callback FOR, returning ER if it fails */
58
+ #define CALLBACK_NOTIFY_(FOR, ER) \
59
+ do { \
60
+ assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
61
+ \
62
+ if (settings->on_##FOR) { \
63
+ if (0 != settings->on_##FOR(parser)) { \
64
+ SET_ERRNO(HPE_CB_##FOR); \
65
+ } \
66
+ \
67
+ /* We either errored above or got paused; get out */ \
68
+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
69
+ return (ER); \
70
+ } \
71
+ } \
72
+ } while (0)
73
+
74
+ /* Run the notify callback FOR and consume the current byte */
75
+ #define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1)
76
+
77
+ /* Run the notify callback FOR and don't consume the current byte */
78
+ #define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data)
79
+
80
+ /* Run data callback FOR with LEN bytes, returning ER if it fails */
81
+ #define CALLBACK_DATA_(FOR, LEN, ER) \
82
+ do { \
83
+ assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
84
+ \
85
+ if (FOR##_mark) { \
86
+ if (settings->on_##FOR) { \
87
+ if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \
88
+ SET_ERRNO(HPE_CB_##FOR); \
89
+ } \
90
+ \
91
+ /* We either errored above or got paused; get out */ \
92
+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
93
+ return (ER); \
94
+ } \
95
+ } \
96
+ FOR##_mark = NULL; \
97
+ } \
98
+ } while (0)
99
+
100
+ /* Run the data callback FOR and consume the current byte */
101
+ #define CALLBACK_DATA(FOR) \
102
+ CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
103
+
104
+ /* Run the data callback FOR and don't consume the current byte */
105
+ #define CALLBACK_DATA_NOADVANCE(FOR) \
106
+ CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
107
+
108
+ /* Set the mark FOR; non-destructive if mark is already set */
109
+ #define MARK(FOR) \
110
+ do { \
111
+ if (!FOR##_mark) { \
112
+ FOR##_mark = p; \
113
+ } \
114
+ } while (0)
115
+
116
+
117
+ #define PROXY_CONNECTION "proxy-connection"
118
+ #define CONNECTION "connection"
119
+ #define CONTENT_LENGTH "content-length"
120
+ #define TRANSFER_ENCODING "transfer-encoding"
121
+ #define UPGRADE "upgrade"
122
+ #define CHUNKED "chunked"
123
+ #define KEEP_ALIVE "keep-alive"
124
+ #define CLOSE "close"
125
+
126
+
127
+ static const char *method_strings[] =
128
+ { "DELETE"
129
+ , "GET"
130
+ , "HEAD"
131
+ , "POST"
132
+ , "PUT"
133
+ , "CONNECT"
134
+ , "OPTIONS"
135
+ , "TRACE"
136
+ , "COPY"
137
+ , "LOCK"
138
+ , "MKCOL"
139
+ , "MOVE"
140
+ , "PROPFIND"
141
+ , "PROPPATCH"
142
+ , "UNLOCK"
143
+ , "REPORT"
144
+ , "MKACTIVITY"
145
+ , "CHECKOUT"
146
+ , "MERGE"
147
+ , "M-SEARCH"
148
+ , "NOTIFY"
149
+ , "SUBSCRIBE"
150
+ , "UNSUBSCRIBE"
151
+ , "PATCH"
152
+ , "PURGE"
153
+ };
154
+
155
+
156
+ /* Tokens as defined by rfc 2616. Also lowercases them.
157
+ * token = 1*<any CHAR except CTLs or separators>
158
+ * separators = "(" | ")" | "<" | ">" | "@"
159
+ * | "," | ";" | ":" | "\" | <">
160
+ * | "/" | "[" | "]" | "?" | "="
161
+ * | "{" | "}" | SP | HT
162
+ */
163
+ static const char tokens[256] = {
164
+ /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
165
+ 0, 0, 0, 0, 0, 0, 0, 0,
166
+ /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
167
+ 0, 0, 0, 0, 0, 0, 0, 0,
168
+ /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
169
+ 0, 0, 0, 0, 0, 0, 0, 0,
170
+ /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
171
+ 0, 0, 0, 0, 0, 0, 0, 0,
172
+ /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
173
+ 0, '!', 0, '#', '$', '%', '&', '\'',
174
+ /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
175
+ 0, 0, '*', '+', 0, '-', '.', 0,
176
+ /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
177
+ '0', '1', '2', '3', '4', '5', '6', '7',
178
+ /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
179
+ '8', '9', 0, 0, 0, 0, 0, 0,
180
+ /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
181
+ 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
182
+ /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
183
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
184
+ /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
185
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
186
+ /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
187
+ 'x', 'y', 'z', 0, 0, 0, '^', '_',
188
+ /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
189
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
190
+ /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
191
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
192
+ /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
193
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
194
+ /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
195
+ 'x', 'y', 'z', 0, '|', 0, '~', 0 };
196
+
197
+
198
+ static const int8_t unhex[256] =
199
+ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
200
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
201
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
202
+ , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
203
+ ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
204
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
205
+ ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
206
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
207
+ };
208
+
209
+
210
+ static const uint8_t normal_url_char[256] = {
211
+ /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
212
+ 0, 0, 0, 0, 0, 0, 0, 0,
213
+ /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
214
+ 0, 0, 0, 0, 0, 0, 0, 0,
215
+ /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
216
+ 0, 0, 0, 0, 0, 0, 0, 0,
217
+ /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
218
+ 0, 0, 0, 0, 0, 0, 0, 0,
219
+ /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
220
+ 0, 1, 1, 0, 1, 1, 1, 1,
221
+ /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
222
+ 1, 1, 1, 1, 1, 1, 1, 1,
223
+ /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
224
+ 1, 1, 1, 1, 1, 1, 1, 1,
225
+ /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
226
+ 1, 1, 1, 1, 1, 1, 1, 0,
227
+ /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
228
+ 1, 1, 1, 1, 1, 1, 1, 1,
229
+ /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
230
+ 1, 1, 1, 1, 1, 1, 1, 1,
231
+ /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
232
+ 1, 1, 1, 1, 1, 1, 1, 1,
233
+ /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
234
+ 1, 1, 1, 1, 1, 1, 1, 1,
235
+ /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
236
+ 1, 1, 1, 1, 1, 1, 1, 1,
237
+ /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
238
+ 1, 1, 1, 1, 1, 1, 1, 1,
239
+ /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
240
+ 1, 1, 1, 1, 1, 1, 1, 1,
241
+ /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
242
+ 1, 1, 1, 1, 1, 1, 1, 0, };
243
+
244
+
245
+ enum state
246
+ { s_dead = 1 /* important that this is > 0 */
247
+
248
+ , s_start_req_or_res
249
+ , s_res_or_resp_H
250
+ , s_start_res
251
+ , s_res_H
252
+ , s_res_HT
253
+ , s_res_HTT
254
+ , s_res_HTTP
255
+ , s_res_first_http_major
256
+ , s_res_http_major
257
+ , s_res_first_http_minor
258
+ , s_res_http_minor
259
+ , s_res_first_status_code
260
+ , s_res_status_code
261
+ , s_res_status
262
+ , s_res_line_almost_done
263
+
264
+ , s_start_req
265
+
266
+ , s_req_method
267
+ , s_req_spaces_before_url
268
+ , s_req_schema
269
+ , s_req_schema_slash
270
+ , s_req_schema_slash_slash
271
+ , s_req_host_start
272
+ , s_req_host_v6_start
273
+ , s_req_host_v6
274
+ , s_req_host_v6_end
275
+ , s_req_host
276
+ , s_req_port_start
277
+ , s_req_port
278
+ , s_req_path
279
+ , s_req_query_string_start
280
+ , s_req_query_string
281
+ , s_req_fragment_start
282
+ , s_req_fragment
283
+ , s_req_http_start
284
+ , s_req_http_H
285
+ , s_req_http_HT
286
+ , s_req_http_HTT
287
+ , s_req_http_HTTP
288
+ , s_req_first_http_major
289
+ , s_req_http_major
290
+ , s_req_first_http_minor
291
+ , s_req_http_minor
292
+ , s_req_line_almost_done
293
+
294
+ , s_header_field_start
295
+ , s_header_field
296
+ , s_header_value_start
297
+ , s_header_value
298
+ , s_header_value_lws
299
+
300
+ , s_header_almost_done
301
+
302
+ , s_chunk_size_start
303
+ , s_chunk_size
304
+ , s_chunk_parameters
305
+ , s_chunk_size_almost_done
306
+
307
+ , s_headers_almost_done
308
+ , s_headers_done
309
+
310
+ /* Important: 's_headers_done' must be the last 'header' state. All
311
+ * states beyond this must be 'body' states. It is used for overflow
312
+ * checking. See the PARSING_HEADER() macro.
313
+ */
314
+
315
+ , s_chunk_data
316
+ , s_chunk_data_almost_done
317
+ , s_chunk_data_done
318
+
319
+ , s_body_identity
320
+ , s_body_identity_eof
321
+
322
+ , s_message_done
323
+ };
324
+
325
+
326
+ #define PARSING_HEADER(state) (state <= s_headers_done)
327
+
328
+
329
+ enum header_states
330
+ { h_general = 0
331
+ , h_C
332
+ , h_CO
333
+ , h_CON
334
+
335
+ , h_matching_connection
336
+ , h_matching_proxy_connection
337
+ , h_matching_content_length
338
+ , h_matching_transfer_encoding
339
+ , h_matching_upgrade
340
+
341
+ , h_connection
342
+ , h_content_length
343
+ , h_transfer_encoding
344
+ , h_upgrade
345
+
346
+ , h_matching_transfer_encoding_chunked
347
+ , h_matching_connection_keep_alive
348
+ , h_matching_connection_close
349
+
350
+ , h_transfer_encoding_chunked
351
+ , h_connection_keep_alive
352
+ , h_connection_close
353
+ };
354
+
355
+
356
+ /* Macros for character classes; depends on strict-mode */
357
+ #define CR '\r'
358
+ #define LF '\n'
359
+ #define LOWER(c) (unsigned char)(c | 0x20)
360
+ #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
361
+ #define IS_NUM(c) ((c) >= '0' && (c) <= '9')
362
+ #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
363
+ #define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
364
+
365
+ #if HTTP_PARSER_STRICT
366
+ #define TOKEN(c) (tokens[(unsigned char)c])
367
+ #define IS_URL_CHAR(c) (normal_url_char[(unsigned char) (c)])
368
+ #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
369
+ #else
370
+ #define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
371
+ #define IS_URL_CHAR(c) \
372
+ (normal_url_char[(unsigned char) (c)] || ((c) & 0x80))
373
+ #define IS_HOST_CHAR(c) \
374
+ (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
375
+ #endif
376
+
377
+
378
+ #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
379
+
380
+
381
+ #if HTTP_PARSER_STRICT
382
+ # define STRICT_CHECK(cond) \
383
+ do { \
384
+ if (cond) { \
385
+ SET_ERRNO(HPE_STRICT); \
386
+ goto error; \
387
+ } \
388
+ } while (0)
389
+ # define NEW_MESSAGE() (_lcb_http_should_keep_alive(parser) ? start_state : s_dead)
390
+ #else
391
+ # define STRICT_CHECK(cond)
392
+ # define NEW_MESSAGE() start_state
393
+ #endif
394
+
395
+
396
+ /* Map errno values to strings for human-readable output */
397
+ #define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
398
+ static struct {
399
+ const char *name;
400
+ const char *description;
401
+ } http_strerror_tab[] = {
402
+ HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
403
+ };
404
+ #undef HTTP_STRERROR_GEN
405
+
406
+ int http_message_needs_eof(http_parser *parser);
407
+
408
+ /* Our URL parser.
409
+ *
410
+ * This is designed to be shared by http_parser_execute() for URL validation,
411
+ * hence it has a state transition + byte-for-byte interface. In addition, it
412
+ * is meant to be embedded in http_parser_parse_url(), which does the dirty
413
+ * work of turning state transitions URL components for its API.
414
+ *
415
+ * This function should only be invoked with non-space characters. It is
416
+ * assumed that the caller cares about (and can detect) the transition between
417
+ * URL and non-URL states by looking for these.
418
+ */
419
+ static enum state
420
+ parse_url_char(enum state s, const char ch)
421
+ {
422
+ assert(!isspace(ch));
423
+
424
+ switch (s) {
425
+ case s_req_spaces_before_url:
426
+ /* Proxied requests are followed by scheme of an absolute URI (alpha).
427
+ * All methods except CONNECT are followed by '/' or '*'.
428
+ */
429
+
430
+ if (ch == '/' || ch == '*') {
431
+ return s_req_path;
432
+ }
433
+
434
+ if (IS_ALPHA(ch)) {
435
+ return s_req_schema;
436
+ }
437
+
438
+ break;
439
+
440
+ case s_req_schema:
441
+ if (IS_ALPHA(ch)) {
442
+ return s;
443
+ }
444
+
445
+ if (ch == ':') {
446
+ return s_req_schema_slash;
447
+ }
448
+
449
+ break;
450
+
451
+ case s_req_schema_slash:
452
+ if (ch == '/') {
453
+ return s_req_schema_slash_slash;
454
+ }
455
+
456
+ break;
457
+
458
+ case s_req_schema_slash_slash:
459
+ if (ch == '/') {
460
+ return s_req_host_start;
461
+ }
462
+
463
+ break;
464
+
465
+ case s_req_host_start:
466
+ if (ch == '[') {
467
+ return s_req_host_v6_start;
468
+ }
469
+
470
+ if (IS_HOST_CHAR(ch)) {
471
+ return s_req_host;
472
+ }
473
+
474
+ break;
475
+
476
+ case s_req_host:
477
+ if (IS_HOST_CHAR(ch)) {
478
+ return s_req_host;
479
+ }
480
+
481
+ /* FALLTHROUGH */
482
+ case s_req_host_v6_end:
483
+ switch (ch) {
484
+ case ':':
485
+ return s_req_port_start;
486
+
487
+ case '/':
488
+ return s_req_path;
489
+
490
+ case '?':
491
+ return s_req_query_string_start;
492
+ }
493
+
494
+ break;
495
+
496
+ case s_req_host_v6:
497
+ if (ch == ']') {
498
+ return s_req_host_v6_end;
499
+ }
500
+
501
+ /* FALLTHROUGH */
502
+ case s_req_host_v6_start:
503
+ if (IS_HEX(ch) || ch == ':') {
504
+ return s_req_host_v6;
505
+ }
506
+ break;
507
+
508
+ case s_req_port:
509
+ switch (ch) {
510
+ case '/':
511
+ return s_req_path;
512
+
513
+ case '?':
514
+ return s_req_query_string_start;
515
+ }
516
+
517
+ /* FALLTHROUGH */
518
+ case s_req_port_start:
519
+ if (IS_NUM(ch)) {
520
+ return s_req_port;
521
+ }
522
+
523
+ break;
524
+
525
+ case s_req_path:
526
+ if (IS_URL_CHAR(ch)) {
527
+ return s;
528
+ }
529
+
530
+ switch (ch) {
531
+ case '?':
532
+ return s_req_query_string_start;
533
+
534
+ case '#':
535
+ return s_req_fragment_start;
536
+ }
537
+
538
+ break;
539
+
540
+ case s_req_query_string_start:
541
+ case s_req_query_string:
542
+ if (IS_URL_CHAR(ch)) {
543
+ return s_req_query_string;
544
+ }
545
+
546
+ switch (ch) {
547
+ case '?':
548
+ /* allow extra '?' in query string */
549
+ return s_req_query_string;
550
+
551
+ case '#':
552
+ return s_req_fragment_start;
553
+ }
554
+
555
+ break;
556
+
557
+ case s_req_fragment_start:
558
+ if (IS_URL_CHAR(ch)) {
559
+ return s_req_fragment;
560
+ }
561
+
562
+ switch (ch) {
563
+ case '?':
564
+ return s_req_fragment;
565
+
566
+ case '#':
567
+ return s;
568
+ }
569
+
570
+ break;
571
+
572
+ case s_req_fragment:
573
+ if (IS_URL_CHAR(ch)) {
574
+ return s;
575
+ }
576
+
577
+ switch (ch) {
578
+ case '?':
579
+ case '#':
580
+ return s;
581
+ }
582
+
583
+ break;
584
+
585
+ default:
586
+ break;
587
+ }
588
+
589
+ /* We should never fall out of the switch above unless there's an error */
590
+ return s_dead;
591
+ }
592
+
593
+ size_t _lcb_http_parser_execute (http_parser *parser,
594
+ const http_parser_settings *settings,
595
+ const char *data,
596
+ size_t len)
597
+ {
598
+ char c, ch;
599
+ int8_t unhex_val;
600
+ const char *p = data;
601
+ const char *header_field_mark = 0;
602
+ const char *header_value_mark = 0;
603
+ const char *url_mark = 0;
604
+ const char *body_mark = 0;
605
+
606
+ /* We're in an error state. Don't bother doing anything. */
607
+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
608
+ return 0;
609
+ }
610
+
611
+ if (len == 0) {
612
+ switch (parser->state) {
613
+ case s_body_identity_eof:
614
+ /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if
615
+ * we got paused.
616
+ */
617
+ CALLBACK_NOTIFY_NOADVANCE(message_complete);
618
+ return 0;
619
+
620
+ case s_dead:
621
+ case s_start_req_or_res:
622
+ case s_start_res:
623
+ case s_start_req:
624
+ return 0;
625
+
626
+ default:
627
+ SET_ERRNO(HPE_INVALID_EOF_STATE);
628
+ return 1;
629
+ }
630
+ }
631
+
632
+
633
+ if (parser->state == s_header_field)
634
+ header_field_mark = data;
635
+ if (parser->state == s_header_value)
636
+ header_value_mark = data;
637
+ switch (parser->state) {
638
+ case s_req_path:
639
+ case s_req_schema:
640
+ case s_req_schema_slash:
641
+ case s_req_schema_slash_slash:
642
+ case s_req_host_start:
643
+ case s_req_host_v6_start:
644
+ case s_req_host_v6:
645
+ case s_req_host_v6_end:
646
+ case s_req_host:
647
+ case s_req_port_start:
648
+ case s_req_port:
649
+ case s_req_query_string_start:
650
+ case s_req_query_string:
651
+ case s_req_fragment_start:
652
+ case s_req_fragment:
653
+ url_mark = data;
654
+ break;
655
+ }
656
+
657
+ for (p=data; p != data + len; p++) {
658
+ ch = *p;
659
+
660
+ if (PARSING_HEADER(parser->state)) {
661
+ ++parser->nread;
662
+ /* Buffer overflow attack */
663
+ if (parser->nread > HTTP_MAX_HEADER_SIZE) {
664
+ SET_ERRNO(HPE_HEADER_OVERFLOW);
665
+ goto error;
666
+ }
667
+ }
668
+
669
+ reexecute_byte:
670
+ switch (parser->state) {
671
+
672
+ case s_dead:
673
+ /* this state is used after a 'Connection: close' message
674
+ * the parser will error out if it reads another message
675
+ */
676
+ if (ch == CR || ch == LF)
677
+ break;
678
+
679
+ SET_ERRNO(HPE_CLOSED_CONNECTION);
680
+ goto error;
681
+
682
+ case s_start_req_or_res:
683
+ {
684
+ if (ch == CR || ch == LF)
685
+ break;
686
+ parser->flags = 0;
687
+ parser->content_length = HTTP_PARSER_ULLONG_MAX;
688
+
689
+ if (ch == 'H') {
690
+ parser->state = s_res_or_resp_H;
691
+
692
+ CALLBACK_NOTIFY(message_begin);
693
+ } else {
694
+ parser->type = HTTP_REQUEST;
695
+ parser->state = s_start_req;
696
+ goto reexecute_byte;
697
+ }
698
+
699
+ break;
700
+ }
701
+
702
+ case s_res_or_resp_H:
703
+ if (ch == 'T') {
704
+ parser->type = HTTP_RESPONSE;
705
+ parser->state = s_res_HT;
706
+ } else {
707
+ if (ch != 'E') {
708
+ SET_ERRNO(HPE_INVALID_CONSTANT);
709
+ goto error;
710
+ }
711
+
712
+ parser->type = HTTP_REQUEST;
713
+ parser->method = HTTP_HEAD;
714
+ parser->index = 2;
715
+ parser->state = s_req_method;
716
+ }
717
+ break;
718
+
719
+ case s_start_res:
720
+ {
721
+ parser->flags = 0;
722
+ parser->content_length = HTTP_PARSER_ULLONG_MAX;
723
+
724
+ switch (ch) {
725
+ case 'H':
726
+ parser->state = s_res_H;
727
+ break;
728
+
729
+ case CR:
730
+ case LF:
731
+ break;
732
+
733
+ default:
734
+ SET_ERRNO(HPE_INVALID_CONSTANT);
735
+ goto error;
736
+ }
737
+
738
+ CALLBACK_NOTIFY(message_begin);
739
+ break;
740
+ }
741
+
742
+ case s_res_H:
743
+ STRICT_CHECK(ch != 'T');
744
+ parser->state = s_res_HT;
745
+ break;
746
+
747
+ case s_res_HT:
748
+ STRICT_CHECK(ch != 'T');
749
+ parser->state = s_res_HTT;
750
+ break;
751
+
752
+ case s_res_HTT:
753
+ STRICT_CHECK(ch != 'P');
754
+ parser->state = s_res_HTTP;
755
+ break;
756
+
757
+ case s_res_HTTP:
758
+ STRICT_CHECK(ch != '/');
759
+ parser->state = s_res_first_http_major;
760
+ break;
761
+
762
+ case s_res_first_http_major:
763
+ if (ch < '0' || ch > '9') {
764
+ SET_ERRNO(HPE_INVALID_VERSION);
765
+ goto error;
766
+ }
767
+
768
+ parser->http_major = ch - '0';
769
+ parser->state = s_res_http_major;
770
+ break;
771
+
772
+ /* major HTTP version or dot */
773
+ case s_res_http_major:
774
+ {
775
+ if (ch == '.') {
776
+ parser->state = s_res_first_http_minor;
777
+ break;
778
+ }
779
+
780
+ if (!IS_NUM(ch)) {
781
+ SET_ERRNO(HPE_INVALID_VERSION);
782
+ goto error;
783
+ }
784
+
785
+ parser->http_major *= 10;
786
+ parser->http_major += ch - '0';
787
+
788
+ if (parser->http_major > 999) {
789
+ SET_ERRNO(HPE_INVALID_VERSION);
790
+ goto error;
791
+ }
792
+
793
+ break;
794
+ }
795
+
796
+ /* first digit of minor HTTP version */
797
+ case s_res_first_http_minor:
798
+ if (!IS_NUM(ch)) {
799
+ SET_ERRNO(HPE_INVALID_VERSION);
800
+ goto error;
801
+ }
802
+
803
+ parser->http_minor = ch - '0';
804
+ parser->state = s_res_http_minor;
805
+ break;
806
+
807
+ /* minor HTTP version or end of request line */
808
+ case s_res_http_minor:
809
+ {
810
+ if (ch == ' ') {
811
+ parser->state = s_res_first_status_code;
812
+ break;
813
+ }
814
+
815
+ if (!IS_NUM(ch)) {
816
+ SET_ERRNO(HPE_INVALID_VERSION);
817
+ goto error;
818
+ }
819
+
820
+ parser->http_minor *= 10;
821
+ parser->http_minor += ch - '0';
822
+
823
+ if (parser->http_minor > 999) {
824
+ SET_ERRNO(HPE_INVALID_VERSION);
825
+ goto error;
826
+ }
827
+
828
+ break;
829
+ }
830
+
831
+ case s_res_first_status_code:
832
+ {
833
+ if (!IS_NUM(ch)) {
834
+ if (ch == ' ') {
835
+ break;
836
+ }
837
+
838
+ SET_ERRNO(HPE_INVALID_STATUS);
839
+ goto error;
840
+ }
841
+ parser->status_code = ch - '0';
842
+ parser->state = s_res_status_code;
843
+ break;
844
+ }
845
+
846
+ case s_res_status_code:
847
+ {
848
+ if (!IS_NUM(ch)) {
849
+ switch (ch) {
850
+ case ' ':
851
+ parser->state = s_res_status;
852
+ break;
853
+ case CR:
854
+ parser->state = s_res_line_almost_done;
855
+ break;
856
+ case LF:
857
+ parser->state = s_header_field_start;
858
+ break;
859
+ default:
860
+ SET_ERRNO(HPE_INVALID_STATUS);
861
+ goto error;
862
+ }
863
+ break;
864
+ }
865
+
866
+ parser->status_code *= 10;
867
+ parser->status_code += ch - '0';
868
+
869
+ if (parser->status_code > 999) {
870
+ SET_ERRNO(HPE_INVALID_STATUS);
871
+ goto error;
872
+ }
873
+
874
+ break;
875
+ }
876
+
877
+ case s_res_status:
878
+ /* the human readable status. e.g. "NOT FOUND"
879
+ * we are not humans so just ignore this */
880
+ if (ch == CR) {
881
+ parser->state = s_res_line_almost_done;
882
+ break;
883
+ }
884
+
885
+ if (ch == LF) {
886
+ parser->state = s_header_field_start;
887
+ break;
888
+ }
889
+ break;
890
+
891
+ case s_res_line_almost_done:
892
+ STRICT_CHECK(ch != LF);
893
+ parser->state = s_header_field_start;
894
+ break;
895
+
896
+ case s_start_req:
897
+ {
898
+ if (ch == CR || ch == LF)
899
+ break;
900
+ parser->flags = 0;
901
+ parser->content_length = HTTP_PARSER_ULLONG_MAX;
902
+
903
+ if (!IS_ALPHA(ch)) {
904
+ SET_ERRNO(HPE_INVALID_METHOD);
905
+ goto error;
906
+ }
907
+
908
+ parser->method = (enum http_method) 0;
909
+ parser->index = 1;
910
+ switch (ch) {
911
+ case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
912
+ case 'D': parser->method = HTTP_DELETE; break;
913
+ case 'G': parser->method = HTTP_GET; break;
914
+ case 'H': parser->method = HTTP_HEAD; break;
915
+ case 'L': parser->method = HTTP_LOCK; break;
916
+ case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
917
+ case 'N': parser->method = HTTP_NOTIFY; break;
918
+ case 'O': parser->method = HTTP_OPTIONS; break;
919
+ case 'P': parser->method = HTTP_POST;
920
+ /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
921
+ break;
922
+ case 'R': parser->method = HTTP_REPORT; break;
923
+ case 'S': parser->method = HTTP_SUBSCRIBE; break;
924
+ case 'T': parser->method = HTTP_TRACE; break;
925
+ case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
926
+ default:
927
+ SET_ERRNO(HPE_INVALID_METHOD);
928
+ goto error;
929
+ }
930
+ parser->state = s_req_method;
931
+
932
+ CALLBACK_NOTIFY(message_begin);
933
+
934
+ break;
935
+ }
936
+
937
+ case s_req_method:
938
+ {
939
+ const char *matcher;
940
+ if (ch == '\0') {
941
+ SET_ERRNO(HPE_INVALID_METHOD);
942
+ goto error;
943
+ }
944
+
945
+ matcher = method_strings[parser->method];
946
+ if (ch == ' ' && matcher[parser->index] == '\0') {
947
+ parser->state = s_req_spaces_before_url;
948
+ } else if (ch == matcher[parser->index]) {
949
+ ; /* nada */
950
+ } else if (parser->method == HTTP_CONNECT) {
951
+ if (parser->index == 1 && ch == 'H') {
952
+ parser->method = HTTP_CHECKOUT;
953
+ } else if (parser->index == 2 && ch == 'P') {
954
+ parser->method = HTTP_COPY;
955
+ } else {
956
+ goto error;
957
+ }
958
+ } else if (parser->method == HTTP_MKCOL) {
959
+ if (parser->index == 1 && ch == 'O') {
960
+ parser->method = HTTP_MOVE;
961
+ } else if (parser->index == 1 && ch == 'E') {
962
+ parser->method = HTTP_MERGE;
963
+ } else if (parser->index == 1 && ch == '-') {
964
+ parser->method = HTTP_MSEARCH;
965
+ } else if (parser->index == 2 && ch == 'A') {
966
+ parser->method = HTTP_MKACTIVITY;
967
+ } else {
968
+ goto error;
969
+ }
970
+ } else if (parser->index == 1 && parser->method == HTTP_POST) {
971
+ if (ch == 'R') {
972
+ parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
973
+ } else if (ch == 'U') {
974
+ parser->method = HTTP_PUT; /* or HTTP_PURGE */
975
+ } else if (ch == 'A') {
976
+ parser->method = HTTP_PATCH;
977
+ } else {
978
+ goto error;
979
+ }
980
+ } else if (parser->index == 2) {
981
+ if (parser->method == HTTP_PUT) {
982
+ if (ch == 'R') parser->method = HTTP_PURGE;
983
+ } else if (parser->method == HTTP_UNLOCK) {
984
+ if (ch == 'S') parser->method = HTTP_UNSUBSCRIBE;
985
+ }
986
+ } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
987
+ parser->method = HTTP_PROPPATCH;
988
+ } else {
989
+ SET_ERRNO(HPE_INVALID_METHOD);
990
+ goto error;
991
+ }
992
+
993
+ ++parser->index;
994
+ break;
995
+ }
996
+
997
+ case s_req_spaces_before_url:
998
+ {
999
+ if (ch == ' ') break;
1000
+
1001
+ MARK(url);
1002
+ if (parser->method == HTTP_CONNECT) {
1003
+ parser->state = s_req_host_start;
1004
+ }
1005
+
1006
+ parser->state = parse_url_char((enum state)parser->state, ch);
1007
+ if (parser->state == s_dead) {
1008
+ SET_ERRNO(HPE_INVALID_URL);
1009
+ goto error;
1010
+ }
1011
+
1012
+ break;
1013
+ }
1014
+
1015
+ case s_req_schema:
1016
+ case s_req_schema_slash:
1017
+ case s_req_schema_slash_slash:
1018
+ case s_req_host_start:
1019
+ case s_req_host_v6_start:
1020
+ case s_req_host_v6:
1021
+ case s_req_port_start:
1022
+ {
1023
+ switch (ch) {
1024
+ /* No whitespace allowed here */
1025
+ case ' ':
1026
+ case CR:
1027
+ case LF:
1028
+ SET_ERRNO(HPE_INVALID_URL);
1029
+ goto error;
1030
+ default:
1031
+ parser->state = parse_url_char((enum state)parser->state, ch);
1032
+ if (parser->state == s_dead) {
1033
+ SET_ERRNO(HPE_INVALID_URL);
1034
+ goto error;
1035
+ }
1036
+ }
1037
+
1038
+ break;
1039
+ }
1040
+
1041
+ case s_req_host:
1042
+ case s_req_host_v6_end:
1043
+ case s_req_port:
1044
+ case s_req_path:
1045
+ case s_req_query_string_start:
1046
+ case s_req_query_string:
1047
+ case s_req_fragment_start:
1048
+ case s_req_fragment:
1049
+ {
1050
+ switch (ch) {
1051
+ case ' ':
1052
+ parser->state = s_req_http_start;
1053
+ CALLBACK_DATA(url);
1054
+ break;
1055
+ case CR:
1056
+ case LF:
1057
+ parser->http_major = 0;
1058
+ parser->http_minor = 9;
1059
+ parser->state = (ch == CR) ?
1060
+ s_req_line_almost_done :
1061
+ s_header_field_start;
1062
+ CALLBACK_DATA(url);
1063
+ break;
1064
+ default:
1065
+ parser->state = parse_url_char((enum state)parser->state, ch);
1066
+ if (parser->state == s_dead) {
1067
+ SET_ERRNO(HPE_INVALID_URL);
1068
+ goto error;
1069
+ }
1070
+ }
1071
+ break;
1072
+ }
1073
+
1074
+ case s_req_http_start:
1075
+ switch (ch) {
1076
+ case 'H':
1077
+ parser->state = s_req_http_H;
1078
+ break;
1079
+ case ' ':
1080
+ break;
1081
+ default:
1082
+ SET_ERRNO(HPE_INVALID_CONSTANT);
1083
+ goto error;
1084
+ }
1085
+ break;
1086
+
1087
+ case s_req_http_H:
1088
+ STRICT_CHECK(ch != 'T');
1089
+ parser->state = s_req_http_HT;
1090
+ break;
1091
+
1092
+ case s_req_http_HT:
1093
+ STRICT_CHECK(ch != 'T');
1094
+ parser->state = s_req_http_HTT;
1095
+ break;
1096
+
1097
+ case s_req_http_HTT:
1098
+ STRICT_CHECK(ch != 'P');
1099
+ parser->state = s_req_http_HTTP;
1100
+ break;
1101
+
1102
+ case s_req_http_HTTP:
1103
+ STRICT_CHECK(ch != '/');
1104
+ parser->state = s_req_first_http_major;
1105
+ break;
1106
+
1107
+ /* first digit of major HTTP version */
1108
+ case s_req_first_http_major:
1109
+ if (ch < '1' || ch > '9') {
1110
+ SET_ERRNO(HPE_INVALID_VERSION);
1111
+ goto error;
1112
+ }
1113
+
1114
+ parser->http_major = ch - '0';
1115
+ parser->state = s_req_http_major;
1116
+ break;
1117
+
1118
+ /* major HTTP version or dot */
1119
+ case s_req_http_major:
1120
+ {
1121
+ if (ch == '.') {
1122
+ parser->state = s_req_first_http_minor;
1123
+ break;
1124
+ }
1125
+
1126
+ if (!IS_NUM(ch)) {
1127
+ SET_ERRNO(HPE_INVALID_VERSION);
1128
+ goto error;
1129
+ }
1130
+
1131
+ parser->http_major *= 10;
1132
+ parser->http_major += ch - '0';
1133
+
1134
+ if (parser->http_major > 999) {
1135
+ SET_ERRNO(HPE_INVALID_VERSION);
1136
+ goto error;
1137
+ }
1138
+
1139
+ break;
1140
+ }
1141
+
1142
+ /* first digit of minor HTTP version */
1143
+ case s_req_first_http_minor:
1144
+ if (!IS_NUM(ch)) {
1145
+ SET_ERRNO(HPE_INVALID_VERSION);
1146
+ goto error;
1147
+ }
1148
+
1149
+ parser->http_minor = ch - '0';
1150
+ parser->state = s_req_http_minor;
1151
+ break;
1152
+
1153
+ /* minor HTTP version or end of request line */
1154
+ case s_req_http_minor:
1155
+ {
1156
+ if (ch == CR) {
1157
+ parser->state = s_req_line_almost_done;
1158
+ break;
1159
+ }
1160
+
1161
+ if (ch == LF) {
1162
+ parser->state = s_header_field_start;
1163
+ break;
1164
+ }
1165
+
1166
+ /* XXX allow spaces after digit? */
1167
+
1168
+ if (!IS_NUM(ch)) {
1169
+ SET_ERRNO(HPE_INVALID_VERSION);
1170
+ goto error;
1171
+ }
1172
+
1173
+ parser->http_minor *= 10;
1174
+ parser->http_minor += ch - '0';
1175
+
1176
+ if (parser->http_minor > 999) {
1177
+ SET_ERRNO(HPE_INVALID_VERSION);
1178
+ goto error;
1179
+ }
1180
+
1181
+ break;
1182
+ }
1183
+
1184
+ /* end of request line */
1185
+ case s_req_line_almost_done:
1186
+ {
1187
+ if (ch != LF) {
1188
+ SET_ERRNO(HPE_LF_EXPECTED);
1189
+ goto error;
1190
+ }
1191
+
1192
+ parser->state = s_header_field_start;
1193
+ break;
1194
+ }
1195
+
1196
+ case s_header_field_start:
1197
+ {
1198
+ if (ch == CR) {
1199
+ parser->state = s_headers_almost_done;
1200
+ break;
1201
+ }
1202
+
1203
+ if (ch == LF) {
1204
+ /* they might be just sending \n instead of \r\n so this would be
1205
+ * the second \n to denote the end of headers*/
1206
+ parser->state = s_headers_almost_done;
1207
+ goto reexecute_byte;
1208
+ }
1209
+
1210
+ c = TOKEN(ch);
1211
+
1212
+ if (!c) {
1213
+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1214
+ goto error;
1215
+ }
1216
+
1217
+ MARK(header_field);
1218
+
1219
+ parser->index = 0;
1220
+ parser->state = s_header_field;
1221
+
1222
+ switch (c) {
1223
+ case 'c':
1224
+ parser->header_state = h_C;
1225
+ break;
1226
+
1227
+ case 'p':
1228
+ parser->header_state = h_matching_proxy_connection;
1229
+ break;
1230
+
1231
+ case 't':
1232
+ parser->header_state = h_matching_transfer_encoding;
1233
+ break;
1234
+
1235
+ case 'u':
1236
+ parser->header_state = h_matching_upgrade;
1237
+ break;
1238
+
1239
+ default:
1240
+ parser->header_state = h_general;
1241
+ break;
1242
+ }
1243
+ break;
1244
+ }
1245
+
1246
+ case s_header_field:
1247
+ {
1248
+ c = TOKEN(ch);
1249
+
1250
+ if (c) {
1251
+ switch (parser->header_state) {
1252
+ case h_general:
1253
+ break;
1254
+
1255
+ case h_C:
1256
+ parser->index++;
1257
+ parser->header_state = (c == 'o' ? h_CO : h_general);
1258
+ break;
1259
+
1260
+ case h_CO:
1261
+ parser->index++;
1262
+ parser->header_state = (c == 'n' ? h_CON : h_general);
1263
+ break;
1264
+
1265
+ case h_CON:
1266
+ parser->index++;
1267
+ switch (c) {
1268
+ case 'n':
1269
+ parser->header_state = h_matching_connection;
1270
+ break;
1271
+ case 't':
1272
+ parser->header_state = h_matching_content_length;
1273
+ break;
1274
+ default:
1275
+ parser->header_state = h_general;
1276
+ break;
1277
+ }
1278
+ break;
1279
+
1280
+ /* connection */
1281
+
1282
+ case h_matching_connection:
1283
+ parser->index++;
1284
+ if (parser->index > sizeof(CONNECTION)-1
1285
+ || c != CONNECTION[parser->index]) {
1286
+ parser->header_state = h_general;
1287
+ } else if (parser->index == sizeof(CONNECTION)-2) {
1288
+ parser->header_state = h_connection;
1289
+ }
1290
+ break;
1291
+
1292
+ /* proxy-connection */
1293
+
1294
+ case h_matching_proxy_connection:
1295
+ parser->index++;
1296
+ if (parser->index > sizeof(PROXY_CONNECTION)-1
1297
+ || c != PROXY_CONNECTION[parser->index]) {
1298
+ parser->header_state = h_general;
1299
+ } else if (parser->index == sizeof(PROXY_CONNECTION)-2) {
1300
+ parser->header_state = h_connection;
1301
+ }
1302
+ break;
1303
+
1304
+ /* content-length */
1305
+
1306
+ case h_matching_content_length:
1307
+ parser->index++;
1308
+ if (parser->index > sizeof(CONTENT_LENGTH)-1
1309
+ || c != CONTENT_LENGTH[parser->index]) {
1310
+ parser->header_state = h_general;
1311
+ } else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
1312
+ parser->header_state = h_content_length;
1313
+ }
1314
+ break;
1315
+
1316
+ /* transfer-encoding */
1317
+
1318
+ case h_matching_transfer_encoding:
1319
+ parser->index++;
1320
+ if (parser->index > sizeof(TRANSFER_ENCODING)-1
1321
+ || c != TRANSFER_ENCODING[parser->index]) {
1322
+ parser->header_state = h_general;
1323
+ } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
1324
+ parser->header_state = h_transfer_encoding;
1325
+ }
1326
+ break;
1327
+
1328
+ /* upgrade */
1329
+
1330
+ case h_matching_upgrade:
1331
+ parser->index++;
1332
+ if (parser->index > sizeof(UPGRADE)-1
1333
+ || c != UPGRADE[parser->index]) {
1334
+ parser->header_state = h_general;
1335
+ } else if (parser->index == sizeof(UPGRADE)-2) {
1336
+ parser->header_state = h_upgrade;
1337
+ }
1338
+ break;
1339
+
1340
+ case h_connection:
1341
+ case h_content_length:
1342
+ case h_transfer_encoding:
1343
+ case h_upgrade:
1344
+ if (ch != ' ') parser->header_state = h_general;
1345
+ break;
1346
+
1347
+ default:
1348
+ assert(0 && "Unknown header_state");
1349
+ break;
1350
+ }
1351
+ break;
1352
+ }
1353
+
1354
+ if (ch == ':') {
1355
+ parser->state = s_header_value_start;
1356
+ CALLBACK_DATA(header_field);
1357
+ break;
1358
+ }
1359
+
1360
+ if (ch == CR) {
1361
+ parser->state = s_header_almost_done;
1362
+ CALLBACK_DATA(header_field);
1363
+ break;
1364
+ }
1365
+
1366
+ if (ch == LF) {
1367
+ parser->state = s_header_field_start;
1368
+ CALLBACK_DATA(header_field);
1369
+ break;
1370
+ }
1371
+
1372
+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1373
+ goto error;
1374
+ }
1375
+
1376
+ case s_header_value_start:
1377
+ {
1378
+ if (ch == ' ' || ch == '\t') break;
1379
+
1380
+ MARK(header_value);
1381
+
1382
+ parser->state = s_header_value;
1383
+ parser->index = 0;
1384
+
1385
+ if (ch == CR) {
1386
+ parser->header_state = h_general;
1387
+ parser->state = s_header_almost_done;
1388
+ CALLBACK_DATA(header_value);
1389
+ break;
1390
+ }
1391
+
1392
+ if (ch == LF) {
1393
+ parser->state = s_header_field_start;
1394
+ CALLBACK_DATA(header_value);
1395
+ break;
1396
+ }
1397
+
1398
+ c = LOWER(ch);
1399
+
1400
+ switch (parser->header_state) {
1401
+ case h_upgrade:
1402
+ parser->flags |= F_UPGRADE;
1403
+ parser->header_state = h_general;
1404
+ break;
1405
+
1406
+ case h_transfer_encoding:
1407
+ /* looking for 'Transfer-Encoding: chunked' */
1408
+ if ('c' == c) {
1409
+ parser->header_state = h_matching_transfer_encoding_chunked;
1410
+ } else {
1411
+ parser->header_state = h_general;
1412
+ }
1413
+ break;
1414
+
1415
+ case h_content_length:
1416
+ if (!IS_NUM(ch)) {
1417
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1418
+ goto error;
1419
+ }
1420
+
1421
+ parser->content_length = ch - '0';
1422
+ break;
1423
+
1424
+ case h_connection:
1425
+ /* looking for 'Connection: keep-alive' */
1426
+ if (c == 'k') {
1427
+ parser->header_state = h_matching_connection_keep_alive;
1428
+ /* looking for 'Connection: close' */
1429
+ } else if (c == 'c') {
1430
+ parser->header_state = h_matching_connection_close;
1431
+ } else {
1432
+ parser->header_state = h_general;
1433
+ }
1434
+ break;
1435
+
1436
+ default:
1437
+ parser->header_state = h_general;
1438
+ break;
1439
+ }
1440
+ break;
1441
+ }
1442
+
1443
+ case s_header_value:
1444
+ {
1445
+
1446
+ if (ch == CR) {
1447
+ parser->state = s_header_almost_done;
1448
+ CALLBACK_DATA(header_value);
1449
+ break;
1450
+ }
1451
+
1452
+ if (ch == LF) {
1453
+ parser->state = s_header_almost_done;
1454
+ CALLBACK_DATA_NOADVANCE(header_value);
1455
+ goto reexecute_byte;
1456
+ }
1457
+
1458
+ c = LOWER(ch);
1459
+
1460
+ switch (parser->header_state) {
1461
+ case h_general:
1462
+ break;
1463
+
1464
+ case h_connection:
1465
+ case h_transfer_encoding:
1466
+ assert(0 && "Shouldn't get here.");
1467
+ break;
1468
+
1469
+ case h_content_length:
1470
+ {
1471
+ uint64_t t;
1472
+
1473
+ if (ch == ' ') break;
1474
+
1475
+ if (!IS_NUM(ch)) {
1476
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1477
+ goto error;
1478
+ }
1479
+
1480
+ t = parser->content_length;
1481
+ t *= 10;
1482
+ t += ch - '0';
1483
+
1484
+ /* Overflow? */
1485
+ if (t < parser->content_length || t == HTTP_PARSER_ULLONG_MAX) {
1486
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1487
+ goto error;
1488
+ }
1489
+
1490
+ parser->content_length = t;
1491
+ break;
1492
+ }
1493
+
1494
+ /* Transfer-Encoding: chunked */
1495
+ case h_matching_transfer_encoding_chunked:
1496
+ parser->index++;
1497
+ if (parser->index > sizeof(CHUNKED)-1
1498
+ || c != CHUNKED[parser->index]) {
1499
+ parser->header_state = h_general;
1500
+ } else if (parser->index == sizeof(CHUNKED)-2) {
1501
+ parser->header_state = h_transfer_encoding_chunked;
1502
+ }
1503
+ break;
1504
+
1505
+ /* looking for 'Connection: keep-alive' */
1506
+ case h_matching_connection_keep_alive:
1507
+ parser->index++;
1508
+ if (parser->index > sizeof(KEEP_ALIVE)-1
1509
+ || c != KEEP_ALIVE[parser->index]) {
1510
+ parser->header_state = h_general;
1511
+ } else if (parser->index == sizeof(KEEP_ALIVE)-2) {
1512
+ parser->header_state = h_connection_keep_alive;
1513
+ }
1514
+ break;
1515
+
1516
+ /* looking for 'Connection: close' */
1517
+ case h_matching_connection_close:
1518
+ parser->index++;
1519
+ if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {
1520
+ parser->header_state = h_general;
1521
+ } else if (parser->index == sizeof(CLOSE)-2) {
1522
+ parser->header_state = h_connection_close;
1523
+ }
1524
+ break;
1525
+
1526
+ case h_transfer_encoding_chunked:
1527
+ case h_connection_keep_alive:
1528
+ case h_connection_close:
1529
+ if (ch != ' ') parser->header_state = h_general;
1530
+ break;
1531
+
1532
+ default:
1533
+ parser->state = s_header_value;
1534
+ parser->header_state = h_general;
1535
+ break;
1536
+ }
1537
+ break;
1538
+ }
1539
+
1540
+ case s_header_almost_done:
1541
+ {
1542
+ STRICT_CHECK(ch != LF);
1543
+
1544
+ parser->state = s_header_value_lws;
1545
+
1546
+ switch (parser->header_state) {
1547
+ case h_connection_keep_alive:
1548
+ parser->flags |= F_CONNECTION_KEEP_ALIVE;
1549
+ break;
1550
+ case h_connection_close:
1551
+ parser->flags |= F_CONNECTION_CLOSE;
1552
+ break;
1553
+ case h_transfer_encoding_chunked:
1554
+ parser->flags |= F_CHUNKED;
1555
+ break;
1556
+ default:
1557
+ break;
1558
+ }
1559
+
1560
+ break;
1561
+ }
1562
+
1563
+ case s_header_value_lws:
1564
+ {
1565
+ if (ch == ' ' || ch == '\t')
1566
+ parser->state = s_header_value_start;
1567
+ else
1568
+ {
1569
+ parser->state = s_header_field_start;
1570
+ goto reexecute_byte;
1571
+ }
1572
+ break;
1573
+ }
1574
+
1575
+ case s_headers_almost_done:
1576
+ {
1577
+ STRICT_CHECK(ch != LF);
1578
+
1579
+ if (parser->flags & F_TRAILING) {
1580
+ /* End of a chunked request */
1581
+ parser->state = NEW_MESSAGE();
1582
+ CALLBACK_NOTIFY(message_complete);
1583
+ break;
1584
+ }
1585
+
1586
+ parser->state = s_headers_done;
1587
+
1588
+ /* Set this here so that on_headers_complete() callbacks can see it */
1589
+ parser->upgrade =
1590
+ (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT);
1591
+
1592
+ /* Here we call the headers_complete callback. This is somewhat
1593
+ * different than other callbacks because if the user returns 1, we
1594
+ * will interpret that as saying that this message has no body. This
1595
+ * is needed for the annoying case of recieving a response to a HEAD
1596
+ * request.
1597
+ *
1598
+ * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
1599
+ * we have to simulate it by handling a change in errno below.
1600
+ */
1601
+ if (settings->on_headers_complete) {
1602
+ switch (settings->on_headers_complete(parser)) {
1603
+ case 0:
1604
+ break;
1605
+
1606
+ case 1:
1607
+ parser->flags |= F_SKIPBODY;
1608
+ break;
1609
+
1610
+ default:
1611
+ SET_ERRNO(HPE_CB_headers_complete);
1612
+ return p - data; /* Error */
1613
+ }
1614
+ }
1615
+
1616
+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
1617
+ return p - data;
1618
+ }
1619
+
1620
+ goto reexecute_byte;
1621
+ }
1622
+
1623
+ case s_headers_done:
1624
+ {
1625
+ STRICT_CHECK(ch != LF);
1626
+
1627
+ parser->nread = 0;
1628
+
1629
+ /* Exit, the rest of the connect is in a different protocol. */
1630
+ if (parser->upgrade) {
1631
+ parser->state = NEW_MESSAGE();
1632
+ CALLBACK_NOTIFY(message_complete);
1633
+ return (p - data) + 1;
1634
+ }
1635
+
1636
+ if (parser->flags & F_SKIPBODY) {
1637
+ parser->state = NEW_MESSAGE();
1638
+ CALLBACK_NOTIFY(message_complete);
1639
+ } else if (parser->flags & F_CHUNKED) {
1640
+ /* chunked encoding - ignore Content-Length header */
1641
+ parser->state = s_chunk_size_start;
1642
+ } else {
1643
+ if (parser->content_length == 0) {
1644
+ /* Content-Length header given but zero: Content-Length: 0\r\n */
1645
+ parser->state = NEW_MESSAGE();
1646
+ CALLBACK_NOTIFY(message_complete);
1647
+ } else if (parser->content_length != HTTP_PARSER_ULLONG_MAX) {
1648
+ /* Content-Length header given and non-zero */
1649
+ parser->state = s_body_identity;
1650
+ } else {
1651
+ if (parser->type == HTTP_REQUEST ||
1652
+ !http_message_needs_eof(parser)) {
1653
+ /* Assume content-length 0 - read the next */
1654
+ parser->state = NEW_MESSAGE();
1655
+ CALLBACK_NOTIFY(message_complete);
1656
+ } else {
1657
+ /* Read body until EOF */
1658
+ parser->state = s_body_identity_eof;
1659
+ }
1660
+ }
1661
+ }
1662
+
1663
+ break;
1664
+ }
1665
+
1666
+ case s_body_identity:
1667
+ {
1668
+ uint64_t to_read = MIN(parser->content_length,
1669
+ (uint64_t) ((data + len) - p));
1670
+
1671
+ assert(parser->content_length != 0
1672
+ && parser->content_length != HTTP_PARSER_ULLONG_MAX);
1673
+
1674
+ /* The difference between advancing content_length and p is because
1675
+ * the latter will automaticaly advance on the next loop iteration.
1676
+ * Further, if content_length ends up at 0, we want to see the last
1677
+ * byte again for our message complete callback.
1678
+ */
1679
+ MARK(body);
1680
+ parser->content_length -= to_read;
1681
+ p += to_read - 1;
1682
+
1683
+ if (parser->content_length == 0) {
1684
+ parser->state = s_message_done;
1685
+
1686
+ /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.
1687
+ *
1688
+ * The alternative to doing this is to wait for the next byte to
1689
+ * trigger the data callback, just as in every other case. The
1690
+ * problem with this is that this makes it difficult for the test
1691
+ * harness to distinguish between complete-on-EOF and
1692
+ * complete-on-length. It's not clear that this distinction is
1693
+ * important for applications, but let's keep it for now.
1694
+ */
1695
+ CALLBACK_DATA_(body, p - body_mark + 1, p - data);
1696
+ goto reexecute_byte;
1697
+ }
1698
+
1699
+ break;
1700
+ }
1701
+
1702
+ /* read until EOF */
1703
+ case s_body_identity_eof:
1704
+ MARK(body);
1705
+ p = data + len - 1;
1706
+
1707
+ break;
1708
+
1709
+ case s_message_done:
1710
+ parser->state = NEW_MESSAGE();
1711
+ CALLBACK_NOTIFY(message_complete);
1712
+ break;
1713
+
1714
+ case s_chunk_size_start:
1715
+ {
1716
+ assert(parser->nread == 1);
1717
+ assert(parser->flags & F_CHUNKED);
1718
+
1719
+ unhex_val = unhex[(unsigned char)ch];
1720
+ if (unhex_val == -1) {
1721
+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1722
+ goto error;
1723
+ }
1724
+
1725
+ parser->content_length = unhex_val;
1726
+ parser->state = s_chunk_size;
1727
+ break;
1728
+ }
1729
+
1730
+ case s_chunk_size:
1731
+ {
1732
+ uint64_t t;
1733
+
1734
+ assert(parser->flags & F_CHUNKED);
1735
+
1736
+ if (ch == CR) {
1737
+ parser->state = s_chunk_size_almost_done;
1738
+ break;
1739
+ }
1740
+
1741
+ unhex_val = unhex[(unsigned char)ch];
1742
+
1743
+ if (unhex_val == -1) {
1744
+ if (ch == ';' || ch == ' ') {
1745
+ parser->state = s_chunk_parameters;
1746
+ break;
1747
+ }
1748
+
1749
+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1750
+ goto error;
1751
+ }
1752
+
1753
+ t = parser->content_length;
1754
+ t *= 16;
1755
+ t += unhex_val;
1756
+
1757
+ /* Overflow? */
1758
+ if (t < parser->content_length || t == HTTP_PARSER_ULLONG_MAX) {
1759
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1760
+ goto error;
1761
+ }
1762
+
1763
+ parser->content_length = t;
1764
+ break;
1765
+ }
1766
+
1767
+ case s_chunk_parameters:
1768
+ {
1769
+ assert(parser->flags & F_CHUNKED);
1770
+ /* just ignore this shit. TODO check for overflow */
1771
+ if (ch == CR) {
1772
+ parser->state = s_chunk_size_almost_done;
1773
+ break;
1774
+ }
1775
+ break;
1776
+ }
1777
+
1778
+ case s_chunk_size_almost_done:
1779
+ {
1780
+ assert(parser->flags & F_CHUNKED);
1781
+ STRICT_CHECK(ch != LF);
1782
+
1783
+ parser->nread = 0;
1784
+
1785
+ if (parser->content_length == 0) {
1786
+ parser->flags |= F_TRAILING;
1787
+ parser->state = s_header_field_start;
1788
+ } else {
1789
+ parser->state = s_chunk_data;
1790
+ }
1791
+ break;
1792
+ }
1793
+
1794
+ case s_chunk_data:
1795
+ {
1796
+ uint64_t to_read = MIN(parser->content_length,
1797
+ (uint64_t) ((data + len) - p));
1798
+
1799
+ assert(parser->flags & F_CHUNKED);
1800
+ assert(parser->content_length != 0
1801
+ && parser->content_length != HTTP_PARSER_ULLONG_MAX);
1802
+
1803
+ /* See the explanation in s_body_identity for why the content
1804
+ * length and data pointers are managed this way.
1805
+ */
1806
+ MARK(body);
1807
+ parser->content_length -= to_read;
1808
+ p += to_read - 1;
1809
+
1810
+ if (parser->content_length == 0) {
1811
+ parser->state = s_chunk_data_almost_done;
1812
+ }
1813
+
1814
+ break;
1815
+ }
1816
+
1817
+ case s_chunk_data_almost_done:
1818
+ assert(parser->flags & F_CHUNKED);
1819
+ assert(parser->content_length == 0);
1820
+ STRICT_CHECK(ch != CR);
1821
+ parser->state = s_chunk_data_done;
1822
+ CALLBACK_DATA(body);
1823
+ break;
1824
+
1825
+ case s_chunk_data_done:
1826
+ assert(parser->flags & F_CHUNKED);
1827
+ STRICT_CHECK(ch != LF);
1828
+ parser->nread = 0;
1829
+ parser->state = s_chunk_size_start;
1830
+ break;
1831
+
1832
+ default:
1833
+ assert(0 && "unhandled state");
1834
+ SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
1835
+ goto error;
1836
+ }
1837
+ }
1838
+
1839
+ /* Run callbacks for any marks that we have leftover after we ran our of
1840
+ * bytes. There should be at most one of these set, so it's OK to invoke
1841
+ * them in series (unset marks will not result in callbacks).
1842
+ *
1843
+ * We use the NOADVANCE() variety of callbacks here because 'p' has already
1844
+ * overflowed 'data' and this allows us to correct for the off-by-one that
1845
+ * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p'
1846
+ * value that's in-bounds).
1847
+ */
1848
+
1849
+ assert(((header_field_mark ? 1 : 0) +
1850
+ (header_value_mark ? 1 : 0) +
1851
+ (url_mark ? 1 : 0) +
1852
+ (body_mark ? 1 : 0)) <= 1);
1853
+
1854
+ CALLBACK_DATA_NOADVANCE(header_field);
1855
+ CALLBACK_DATA_NOADVANCE(header_value);
1856
+ CALLBACK_DATA_NOADVANCE(url);
1857
+ CALLBACK_DATA_NOADVANCE(body);
1858
+
1859
+ return len;
1860
+
1861
+ error:
1862
+ if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
1863
+ SET_ERRNO(HPE_UNKNOWN);
1864
+ }
1865
+
1866
+ return (p - data);
1867
+ }
1868
+
1869
+
1870
+ /* Does the parser need to see an EOF to find the end of the message? */
1871
+ int
1872
+ http_message_needs_eof (http_parser *parser)
1873
+ {
1874
+ if (parser->type == HTTP_REQUEST) {
1875
+ return 0;
1876
+ }
1877
+
1878
+ /* See RFC 2616 section 4.4 */
1879
+ if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
1880
+ parser->status_code == 204 || /* No Content */
1881
+ parser->status_code == 304 || /* Not Modified */
1882
+ parser->flags & F_SKIPBODY) { /* response to a HEAD request */
1883
+ return 0;
1884
+ }
1885
+
1886
+ if ((parser->flags & F_CHUNKED) || parser->content_length != HTTP_PARSER_ULLONG_MAX) {
1887
+ return 0;
1888
+ }
1889
+
1890
+ return 1;
1891
+ }
1892
+
1893
+
1894
+ int
1895
+ _lcb_http_should_keep_alive (http_parser *parser)
1896
+ {
1897
+ if (parser->http_major > 0 && parser->http_minor > 0) {
1898
+ /* HTTP/1.1 */
1899
+ if (parser->flags & F_CONNECTION_CLOSE) {
1900
+ return 0;
1901
+ }
1902
+ } else {
1903
+ /* HTTP/1.0 or earlier */
1904
+ if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
1905
+ return 0;
1906
+ }
1907
+ }
1908
+
1909
+ return !http_message_needs_eof(parser);
1910
+ }
1911
+
1912
+
1913
+ const char * _lcb_http_method_str (enum http_method m)
1914
+ {
1915
+ return method_strings[m];
1916
+ }
1917
+
1918
+
1919
+ void
1920
+ _lcb_http_parser_init (http_parser *parser, enum http_parser_type t)
1921
+ {
1922
+ void *data = parser->data; /* preserve application data */
1923
+ memset(parser, 0, sizeof(*parser));
1924
+ parser->data = data;
1925
+ parser->type = t;
1926
+ parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
1927
+ parser->http_errno = HPE_OK;
1928
+ }
1929
+
1930
+ const char *
1931
+ _lcb_http_errno_name(enum http_errno err) {
1932
+ assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
1933
+ return http_strerror_tab[err].name;
1934
+ }
1935
+
1936
+ const char *
1937
+ _lcb_http_errno_description(enum http_errno err) {
1938
+ assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
1939
+ return http_strerror_tab[err].description;
1940
+ }
1941
+
1942
+ int
1943
+ _lcb_http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
1944
+ struct http_parser_url *u)
1945
+ {
1946
+ enum state s;
1947
+ const char *p;
1948
+ enum http_parser_url_fields uf, old_uf;
1949
+
1950
+ u->port = u->field_set = 0;
1951
+ s = is_connect ? s_req_host_start : s_req_spaces_before_url;
1952
+ uf = old_uf = UF_MAX;
1953
+
1954
+ for (p = buf; p < buf + buflen; p++) {
1955
+ s = parse_url_char(s, *p);
1956
+
1957
+ /* Figure out the next field that we're operating on */
1958
+ switch (s) {
1959
+ case s_dead:
1960
+ return 1;
1961
+
1962
+ /* Skip delimeters */
1963
+ case s_req_schema_slash:
1964
+ case s_req_schema_slash_slash:
1965
+ case s_req_host_start:
1966
+ case s_req_host_v6_start:
1967
+ case s_req_host_v6_end:
1968
+ case s_req_port_start:
1969
+ case s_req_query_string_start:
1970
+ case s_req_fragment_start:
1971
+ continue;
1972
+
1973
+ case s_req_schema:
1974
+ uf = UF_SCHEMA;
1975
+ break;
1976
+
1977
+ case s_req_host:
1978
+ case s_req_host_v6:
1979
+ uf = UF_HOST;
1980
+ break;
1981
+
1982
+ case s_req_port:
1983
+ uf = UF_PORT;
1984
+ break;
1985
+
1986
+ case s_req_path:
1987
+ uf = UF_PATH;
1988
+ break;
1989
+
1990
+ case s_req_query_string:
1991
+ uf = UF_QUERY;
1992
+ break;
1993
+
1994
+ case s_req_fragment:
1995
+ uf = UF_FRAGMENT;
1996
+ break;
1997
+
1998
+ default:
1999
+ assert(!"Unexpected state");
2000
+ return 1;
2001
+ }
2002
+
2003
+ /* Nothing's changed; soldier on */
2004
+ if (uf == old_uf) {
2005
+ u->field_data[uf].len++;
2006
+ continue;
2007
+ }
2008
+
2009
+ u->field_data[uf].off = (uint16_t)(p - buf);
2010
+ u->field_data[uf].len = 1;
2011
+
2012
+ u->field_set |= (1 << uf);
2013
+ old_uf = uf;
2014
+ }
2015
+
2016
+ /* CONNECT requests can only contain "hostname:port" */
2017
+ if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {
2018
+ return 1;
2019
+ }
2020
+
2021
+ /* Make sure we don't end somewhere unexpected */
2022
+ switch (s) {
2023
+ case s_req_host_v6_start:
2024
+ case s_req_host_v6:
2025
+ case s_req_host_v6_end:
2026
+ case s_req_host:
2027
+ case s_req_port_start:
2028
+ return 1;
2029
+ default:
2030
+ break;
2031
+ }
2032
+
2033
+ if (u->field_set & (1 << UF_PORT)) {
2034
+ /* Don't bother with endp; we've already validated the string */
2035
+ unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
2036
+
2037
+ /* Ports have a max value of 2^16 */
2038
+ if (v > 0xffff) {
2039
+ return 1;
2040
+ }
2041
+
2042
+ u->port = (uint16_t) v;
2043
+ }
2044
+
2045
+ return 0;
2046
+ }
2047
+
2048
+ void
2049
+ _lcb_http_parser_pause(http_parser *parser, int paused) {
2050
+ /* Users should only be pausing/unpausing a parser that is not in an error
2051
+ * state. In non-debug builds, there's not much that we can do about this
2052
+ * other than ignore it.
2053
+ */
2054
+ if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
2055
+ HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
2056
+ SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
2057
+ } else {
2058
+ assert(0 && "Attempting to pause parser in error state");
2059
+ }
2060
+ }