rugged 0.1.2 → 0.16.0b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (277) hide show
  1. data/README.md +25 -36
  2. data/Rakefile +20 -98
  3. data/ext/rugged/extconf.rb +44 -4
  4. data/ext/rugged/remote.c +215 -0
  5. data/ext/rugged/rugged.c +171 -0
  6. data/ext/rugged/rugged.h +126 -0
  7. data/ext/rugged/rugged_blob.c +99 -0
  8. data/ext/rugged/rugged_commit.c +224 -0
  9. data/ext/rugged/rugged_config.c +238 -0
  10. data/ext/rugged/rugged_index.c +440 -0
  11. data/ext/rugged/rugged_object.c +203 -0
  12. data/ext/rugged/rugged_reference.c +401 -0
  13. data/ext/rugged/rugged_repo.c +482 -0
  14. data/ext/rugged/rugged_revwalk.c +138 -0
  15. data/ext/rugged/rugged_signature.c +80 -0
  16. data/ext/rugged/rugged_tag.c +216 -0
  17. data/ext/rugged/rugged_tree.c +322 -0
  18. data/ext/rugged/vendor/libgit2-dist.tar.gz +0 -0
  19. data/ext/rugged/vendor/libgit2-dist/deps/http-parser/http_parser.c +1778 -0
  20. data/ext/rugged/vendor/libgit2-dist/deps/http-parser/http_parser.h +267 -0
  21. data/ext/rugged/vendor/libgit2-dist/deps/zlib/adler32.c +169 -0
  22. data/ext/rugged/vendor/libgit2-dist/deps/zlib/crc32.c +442 -0
  23. data/ext/rugged/vendor/libgit2-dist/deps/zlib/crc32.h +441 -0
  24. data/ext/rugged/vendor/libgit2-dist/deps/zlib/deflate.c +1834 -0
  25. data/ext/rugged/vendor/libgit2-dist/deps/zlib/deflate.h +342 -0
  26. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inffast.c +340 -0
  27. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inffast.h +11 -0
  28. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inffixed.h +94 -0
  29. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inflate.c +1480 -0
  30. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inflate.h +122 -0
  31. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inftrees.c +330 -0
  32. data/ext/rugged/vendor/libgit2-dist/deps/zlib/inftrees.h +62 -0
  33. data/ext/rugged/vendor/libgit2-dist/deps/zlib/trees.c +1244 -0
  34. data/ext/rugged/vendor/libgit2-dist/deps/zlib/trees.h +128 -0
  35. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zconf.h +54 -0
  36. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zlib.h +1613 -0
  37. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zutil.c +318 -0
  38. data/ext/rugged/vendor/libgit2-dist/deps/zlib/zutil.h +274 -0
  39. data/ext/rugged/vendor/libgit2-dist/examples/general.c +451 -0
  40. data/ext/rugged/vendor/libgit2-dist/examples/network/common.h +14 -0
  41. data/ext/rugged/vendor/libgit2-dist/examples/network/fetch.c +97 -0
  42. data/ext/rugged/vendor/libgit2-dist/examples/network/git2.c +58 -0
  43. data/ext/rugged/vendor/libgit2-dist/examples/network/index-pack.c +47 -0
  44. data/ext/rugged/vendor/libgit2-dist/examples/network/ls-remote.c +76 -0
  45. data/ext/rugged/vendor/libgit2-dist/examples/showindex.c +43 -0
  46. data/ext/rugged/vendor/libgit2-dist/include/git2.h +44 -0
  47. data/ext/rugged/vendor/libgit2-dist/include/git2/blob.h +120 -0
  48. data/ext/rugged/vendor/libgit2-dist/include/git2/branch.h +15 -0
  49. data/ext/rugged/vendor/libgit2-dist/include/git2/commit.h +263 -0
  50. data/ext/rugged/vendor/libgit2-dist/include/git2/common.h +103 -0
  51. data/ext/rugged/vendor/libgit2-dist/include/git2/config.h +278 -0
  52. data/ext/rugged/vendor/libgit2-dist/include/git2/errors.h +144 -0
  53. data/ext/rugged/vendor/libgit2-dist/include/git2/index.h +306 -0
  54. data/ext/rugged/vendor/libgit2-dist/include/git2/indexer.h +76 -0
  55. data/ext/rugged/vendor/libgit2-dist/include/git2/inttypes.h +305 -0
  56. data/ext/rugged/vendor/libgit2-dist/include/git2/net.h +51 -0
  57. data/ext/rugged/vendor/libgit2-dist/include/git2/object.h +173 -0
  58. data/ext/rugged/vendor/libgit2-dist/include/git2/odb.h +331 -0
  59. data/ext/rugged/vendor/libgit2-dist/include/git2/odb_backend.h +100 -0
  60. data/ext/rugged/vendor/libgit2-dist/include/git2/oid.h +218 -0
  61. data/ext/rugged/vendor/libgit2-dist/include/git2/reflog.h +128 -0
  62. data/ext/rugged/vendor/libgit2-dist/include/git2/refs.h +309 -0
  63. data/ext/rugged/vendor/libgit2-dist/include/git2/refspec.h +60 -0
  64. data/ext/rugged/vendor/libgit2-dist/include/git2/remote.h +176 -0
  65. data/ext/rugged/vendor/libgit2-dist/include/git2/repository.h +290 -0
  66. data/ext/rugged/vendor/libgit2-dist/include/git2/revwalk.h +169 -0
  67. data/ext/rugged/vendor/libgit2-dist/include/git2/signature.h +65 -0
  68. data/ext/rugged/vendor/libgit2-dist/include/git2/status.h +63 -0
  69. data/ext/rugged/vendor/libgit2-dist/include/git2/stdint.h +247 -0
  70. data/ext/rugged/vendor/libgit2-dist/include/git2/tag.h +279 -0
  71. data/ext/rugged/vendor/libgit2-dist/include/git2/threads.h +48 -0
  72. data/ext/rugged/vendor/libgit2-dist/include/git2/tree.h +318 -0
  73. data/ext/rugged/vendor/libgit2-dist/include/git2/types.h +169 -0
  74. data/ext/rugged/vendor/libgit2-dist/include/git2/version.h +15 -0
  75. data/ext/rugged/vendor/libgit2-dist/include/git2/windows.h +59 -0
  76. data/ext/rugged/vendor/libgit2-dist/include/git2/zlib.h +40 -0
  77. data/ext/rugged/vendor/libgit2-dist/src/blob.c +135 -0
  78. data/ext/rugged/vendor/libgit2-dist/src/blob.h +23 -0
  79. data/ext/rugged/vendor/libgit2-dist/src/bswap.h +97 -0
  80. data/ext/rugged/vendor/libgit2-dist/src/buffer.c +113 -0
  81. data/ext/rugged/vendor/libgit2-dist/src/buffer.h +32 -0
  82. data/ext/rugged/vendor/libgit2-dist/src/cache.c +111 -0
  83. data/ext/rugged/vendor/libgit2-dist/src/cache.h +64 -0
  84. data/ext/rugged/vendor/libgit2-dist/src/cc-compat.h +67 -0
  85. data/ext/rugged/vendor/libgit2-dist/src/commit.c +299 -0
  86. data/ext/rugged/vendor/libgit2-dist/src/commit.h +34 -0
  87. data/ext/rugged/vendor/libgit2-dist/src/common.h +64 -0
  88. data/ext/rugged/vendor/libgit2-dist/src/config.c +418 -0
  89. data/ext/rugged/vendor/libgit2-dist/src/config.h +24 -0
  90. data/ext/rugged/vendor/libgit2-dist/src/config_file.c +1210 -0
  91. data/ext/rugged/vendor/libgit2-dist/src/delta-apply.c +115 -0
  92. data/ext/rugged/vendor/libgit2-dist/src/delta-apply.h +33 -0
  93. data/ext/rugged/vendor/libgit2-dist/src/dir.h +47 -0
  94. data/ext/rugged/vendor/libgit2-dist/src/errors.c +104 -0
  95. data/ext/rugged/vendor/libgit2-dist/src/fetch.c +172 -0
  96. data/ext/rugged/vendor/libgit2-dist/src/fetch.h +18 -0
  97. data/ext/rugged/vendor/libgit2-dist/src/filebuf.c +400 -0
  98. data/ext/rugged/vendor/libgit2-dist/src/filebuf.h +72 -0
  99. data/ext/rugged/vendor/libgit2-dist/src/fileops.c +358 -0
  100. data/ext/rugged/vendor/libgit2-dist/src/fileops.h +151 -0
  101. data/ext/rugged/vendor/libgit2-dist/src/global.c +134 -0
  102. data/ext/rugged/vendor/libgit2-dist/src/global.h +24 -0
  103. data/ext/rugged/vendor/libgit2-dist/src/hash.c +74 -0
  104. data/ext/rugged/vendor/libgit2-dist/src/hash.h +29 -0
  105. data/ext/rugged/vendor/libgit2-dist/src/hashtable.c +243 -0
  106. data/ext/rugged/vendor/libgit2-dist/src/hashtable.h +80 -0
  107. data/ext/rugged/vendor/libgit2-dist/src/index.c +918 -0
  108. data/ext/rugged/vendor/libgit2-dist/src/index.h +34 -0
  109. data/ext/rugged/vendor/libgit2-dist/src/indexer.c +401 -0
  110. data/ext/rugged/vendor/libgit2-dist/src/map.h +37 -0
  111. data/ext/rugged/vendor/libgit2-dist/src/mwindow.c +272 -0
  112. data/ext/rugged/vendor/libgit2-dist/src/mwindow.h +45 -0
  113. data/ext/rugged/vendor/libgit2-dist/src/netops.c +198 -0
  114. data/ext/rugged/vendor/libgit2-dist/src/netops.h +36 -0
  115. data/ext/rugged/vendor/libgit2-dist/src/object.c +295 -0
  116. data/ext/rugged/vendor/libgit2-dist/src/odb.c +672 -0
  117. data/ext/rugged/vendor/libgit2-dist/src/odb.h +43 -0
  118. data/ext/rugged/vendor/libgit2-dist/src/odb_loose.c +855 -0
  119. data/ext/rugged/vendor/libgit2-dist/src/odb_pack.c +485 -0
  120. data/ext/rugged/vendor/libgit2-dist/src/oid.c +388 -0
  121. data/ext/rugged/vendor/libgit2-dist/src/pack.c +788 -0
  122. data/ext/rugged/vendor/libgit2-dist/src/pack.h +99 -0
  123. data/ext/rugged/vendor/libgit2-dist/src/path.c +270 -0
  124. data/ext/rugged/vendor/libgit2-dist/src/path.h +84 -0
  125. data/ext/rugged/vendor/libgit2-dist/src/pkt.c +426 -0
  126. data/ext/rugged/vendor/libgit2-dist/src/pkt.h +77 -0
  127. data/ext/rugged/vendor/libgit2-dist/src/posix.c +94 -0
  128. data/ext/rugged/vendor/libgit2-dist/src/posix.h +69 -0
  129. data/ext/rugged/vendor/libgit2-dist/src/ppc/sha1.c +70 -0
  130. data/ext/rugged/vendor/libgit2-dist/src/ppc/sha1.h +26 -0
  131. data/ext/rugged/vendor/libgit2-dist/src/pqueue.c +141 -0
  132. data/ext/rugged/vendor/libgit2-dist/src/pqueue.h +81 -0
  133. data/ext/rugged/vendor/libgit2-dist/src/protocol.c +50 -0
  134. data/ext/rugged/vendor/libgit2-dist/src/protocol.h +23 -0
  135. data/ext/rugged/vendor/libgit2-dist/src/reflog.c +318 -0
  136. data/ext/rugged/vendor/libgit2-dist/src/reflog.h +34 -0
  137. data/ext/rugged/vendor/libgit2-dist/src/refs.c +1693 -0
  138. data/ext/rugged/vendor/libgit2-dist/src/refs.h +58 -0
  139. data/ext/rugged/vendor/libgit2-dist/src/refspec.c +95 -0
  140. data/ext/rugged/vendor/libgit2-dist/src/refspec.h +23 -0
  141. data/ext/rugged/vendor/libgit2-dist/src/remote.c +339 -0
  142. data/ext/rugged/vendor/libgit2-dist/src/remote.h +25 -0
  143. data/ext/rugged/vendor/libgit2-dist/src/repository.c +849 -0
  144. data/ext/rugged/vendor/libgit2-dist/src/repository.h +60 -0
  145. data/ext/rugged/vendor/libgit2-dist/src/revwalk.c +569 -0
  146. data/ext/rugged/vendor/libgit2-dist/src/sha1.c +280 -0
  147. data/ext/rugged/vendor/libgit2-dist/src/sha1.h +21 -0
  148. data/ext/rugged/vendor/libgit2-dist/src/sha1_lookup.c +177 -0
  149. data/ext/rugged/vendor/libgit2-dist/src/sha1_lookup.h +18 -0
  150. data/ext/rugged/vendor/libgit2-dist/src/signature.c +335 -0
  151. data/ext/rugged/vendor/libgit2-dist/src/signature.h +18 -0
  152. data/ext/rugged/vendor/libgit2-dist/src/status.c +696 -0
  153. data/ext/rugged/vendor/libgit2-dist/src/tag.c +446 -0
  154. data/ext/rugged/vendor/libgit2-dist/src/tag.h +28 -0
  155. data/ext/rugged/vendor/libgit2-dist/src/thread-utils.c +55 -0
  156. data/ext/rugged/vendor/libgit2-dist/src/thread-utils.h +108 -0
  157. data/ext/rugged/vendor/libgit2-dist/src/transport.c +85 -0
  158. data/ext/rugged/vendor/libgit2-dist/src/transport.h +110 -0
  159. data/ext/rugged/vendor/libgit2-dist/src/transports/git.c +502 -0
  160. data/ext/rugged/vendor/libgit2-dist/src/transports/http.c +756 -0
  161. data/ext/rugged/vendor/libgit2-dist/src/transports/local.c +235 -0
  162. data/ext/rugged/vendor/libgit2-dist/src/tree-cache.c +201 -0
  163. data/ext/rugged/vendor/libgit2-dist/src/tree-cache.h +31 -0
  164. data/ext/rugged/vendor/libgit2-dist/src/tree.c +758 -0
  165. data/ext/rugged/vendor/libgit2-dist/src/tree.h +37 -0
  166. data/ext/rugged/vendor/libgit2-dist/src/tsort.c +365 -0
  167. data/ext/rugged/vendor/libgit2-dist/src/unix/map.c +70 -0
  168. data/ext/rugged/vendor/libgit2-dist/src/unix/posix.h +25 -0
  169. data/ext/rugged/vendor/libgit2-dist/src/util.c +381 -0
  170. data/ext/rugged/vendor/libgit2-dist/src/util.h +137 -0
  171. data/ext/rugged/vendor/libgit2-dist/src/vector.c +174 -0
  172. data/ext/rugged/vendor/libgit2-dist/src/vector.h +45 -0
  173. data/ext/rugged/vendor/libgit2-dist/src/win32/dir.c +115 -0
  174. data/ext/rugged/vendor/libgit2-dist/src/win32/fnmatch.c +180 -0
  175. data/ext/rugged/vendor/libgit2-dist/src/win32/fnmatch.h +27 -0
  176. data/ext/rugged/vendor/libgit2-dist/src/win32/map.c +131 -0
  177. data/ext/rugged/vendor/libgit2-dist/src/win32/mingw-compat.h +24 -0
  178. data/ext/rugged/vendor/libgit2-dist/src/win32/msvc-compat.h +38 -0
  179. data/ext/rugged/vendor/libgit2-dist/src/win32/posix.h +53 -0
  180. data/ext/rugged/vendor/libgit2-dist/src/win32/posix_w32.c +404 -0
  181. data/ext/rugged/vendor/libgit2-dist/src/win32/pthread.c +65 -0
  182. data/ext/rugged/vendor/libgit2-dist/src/win32/pthread.h +40 -0
  183. data/ext/rugged/vendor/libgit2-dist/src/win32/utf-conv.c +88 -0
  184. data/ext/rugged/vendor/libgit2-dist/src/win32/utf-conv.h +17 -0
  185. data/ext/rugged/vendor/libgit2-dist/tests-clay/buf/basic.c +29 -0
  186. data/ext/rugged/vendor/libgit2-dist/tests-clay/clay.h +187 -0
  187. data/ext/rugged/vendor/libgit2-dist/tests-clay/clay_libgit2.h +28 -0
  188. data/ext/rugged/vendor/libgit2-dist/tests-clay/clay_main.c +1073 -0
  189. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/add.c +37 -0
  190. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/new.c +36 -0
  191. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/read.c +209 -0
  192. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/stress.c +39 -0
  193. data/ext/rugged/vendor/libgit2-dist/tests-clay/config/write.c +77 -0
  194. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/dirent.c +222 -0
  195. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/filebuf.c +106 -0
  196. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/oid.c +18 -0
  197. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/path.c +139 -0
  198. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/rmdir.c +50 -0
  199. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/string.c +28 -0
  200. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/strtol.c +37 -0
  201. data/ext/rugged/vendor/libgit2-dist/tests-clay/core/vector.c +66 -0
  202. data/ext/rugged/vendor/libgit2-dist/tests-clay/index/rename.c +60 -0
  203. data/ext/rugged/vendor/libgit2-dist/tests-clay/network/remotes.c +50 -0
  204. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/chars.c +52 -0
  205. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/compare.c +124 -0
  206. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/convert.c +75 -0
  207. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/data.h +323 -0
  208. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/fromstr.c +30 -0
  209. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/hash.c +162 -0
  210. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/short.c +94 -0
  211. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/size.c +13 -0
  212. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/raw/type2string.c +54 -0
  213. data/ext/rugged/vendor/libgit2-dist/tests-clay/object/tree/frompath.c +75 -0
  214. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/loose.c +84 -0
  215. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/loose_data.h +522 -0
  216. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/pack_data.h +151 -0
  217. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/packed.c +78 -0
  218. data/ext/rugged/vendor/libgit2-dist/tests-clay/odb/sorting.c +71 -0
  219. data/ext/rugged/vendor/libgit2-dist/tests-clay/repo/getters.c +68 -0
  220. data/ext/rugged/vendor/libgit2-dist/tests-clay/repo/init.c +104 -0
  221. data/ext/rugged/vendor/libgit2-dist/tests-clay/repo/open.c +54 -0
  222. data/ext/rugged/vendor/libgit2-dist/tests-clay/status/single.c +38 -0
  223. data/ext/rugged/vendor/libgit2-dist/tests-clay/status/status_data.h +48 -0
  224. data/ext/rugged/vendor/libgit2-dist/tests-clay/status/worktree.c +124 -0
  225. data/ext/rugged/vendor/libgit2-dist/tests/t00-core.c +628 -0
  226. data/ext/rugged/vendor/libgit2-dist/tests/t01-data.h +322 -0
  227. data/ext/rugged/vendor/libgit2-dist/tests/t01-rawobj.c +638 -0
  228. data/ext/rugged/vendor/libgit2-dist/tests/t03-data.h +344 -0
  229. data/ext/rugged/vendor/libgit2-dist/tests/t03-objwrite.c +255 -0
  230. data/ext/rugged/vendor/libgit2-dist/tests/t04-commit.c +788 -0
  231. data/ext/rugged/vendor/libgit2-dist/tests/t05-revwalk.c +140 -0
  232. data/ext/rugged/vendor/libgit2-dist/tests/t06-index.c +219 -0
  233. data/ext/rugged/vendor/libgit2-dist/tests/t07-hashtable.c +192 -0
  234. data/ext/rugged/vendor/libgit2-dist/tests/t08-tag.c +357 -0
  235. data/ext/rugged/vendor/libgit2-dist/tests/t09-tree.c +221 -0
  236. data/ext/rugged/vendor/libgit2-dist/tests/t10-refs.c +1294 -0
  237. data/ext/rugged/vendor/libgit2-dist/tests/t12-repo.c +174 -0
  238. data/ext/rugged/vendor/libgit2-dist/tests/t13-threads.c +41 -0
  239. data/ext/rugged/vendor/libgit2-dist/tests/t17-bufs.c +61 -0
  240. data/ext/rugged/vendor/libgit2-dist/tests/t18-status.c +448 -0
  241. data/ext/rugged/vendor/libgit2-dist/tests/test_helpers.c +310 -0
  242. data/ext/rugged/vendor/libgit2-dist/tests/test_helpers.h +83 -0
  243. data/ext/rugged/vendor/libgit2-dist/tests/test_lib.c +198 -0
  244. data/ext/rugged/vendor/libgit2-dist/tests/test_lib.h +54 -0
  245. data/ext/rugged/vendor/libgit2-dist/tests/test_main.c +89 -0
  246. data/lib/rugged.rb +4 -3
  247. data/lib/rugged/index.rb +0 -8
  248. data/lib/rugged/objects.rb +45 -0
  249. data/lib/rugged/repository.rb +29 -0
  250. data/lib/rugged/tree.rb +16 -6
  251. data/lib/rugged/version.rb +1 -1
  252. data/lib/rugged/walker.rb +5 -0
  253. data/test/blob_test.rb +18 -14
  254. data/test/commit_test.rb +28 -26
  255. data/test/coverage/HEAD.json +1 -0
  256. data/test/coverage/cover.rb +106 -0
  257. data/test/fixtures/testrepo.git/refs/heads/new_name +1 -0
  258. data/test/index_test.rb +101 -78
  259. data/test/lib_test.rb +4 -4
  260. data/test/object_test.rb +3 -3
  261. data/test/reference_test.rb +75 -0
  262. data/test/remote_test.rb +19 -0
  263. data/test/repo_pack_test.rb +4 -4
  264. data/test/repo_test.rb +44 -15
  265. data/test/tag_test.rb +7 -17
  266. data/test/test_helper.rb +24 -5
  267. data/test/tree_test.rb +30 -12
  268. data/test/walker_test.rb +40 -31
  269. metadata +273 -50
  270. data/lib/rugged/person.rb +0 -20
  271. data/lib/rugged/tree_entry.rb +0 -9
  272. data/test/fixtures/testrepo.git/objects/1d/83f106355e4309a293e42ad2a2c4b8bdbe77ae +0 -0
  273. data/test/fixtures/testrepo.git/objects/2f/3321418db5b2a841375b8b70880a8ab5a4148f +0 -0
  274. data/test/fixtures/testrepo.git/objects/36/9b00a7700cca3a506d79e301d6ad8bf735d9ee +0 -3
  275. data/test/fixtures/testrepo.git/objects/3d/b1b5ceace59ff65279757003763046fd4cbbe6 +0 -0
  276. data/test/fixtures/testrepo.git/objects/4c/d1604907792e2c43e03dcec1216f99d63e68c4 +0 -3
  277. data/test/fixtures/testrepo.git/objects/e0/f46d77041c149296549b01ed4a18b02c4b7400 +0 -0
@@ -0,0 +1,1778 @@
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
+
28
+
29
+ #ifndef MIN
30
+ # define MIN(a,b) ((a) < (b) ? (a) : (b))
31
+ #endif
32
+
33
+
34
+ #if HTTP_PARSER_DEBUG
35
+ #define SET_ERRNO(e) \
36
+ do { \
37
+ parser->http_errno = (e); \
38
+ parser->error_lineno = __LINE__; \
39
+ } while (0)
40
+ #else
41
+ #define SET_ERRNO(e) \
42
+ do { \
43
+ parser->http_errno = (e); \
44
+ } while(0)
45
+ #endif
46
+
47
+
48
+ #define CALLBACK2(FOR) \
49
+ do { \
50
+ if (settings->on_##FOR) { \
51
+ if (0 != settings->on_##FOR(parser)) { \
52
+ SET_ERRNO(HPE_CB_##FOR); \
53
+ return (p - data); \
54
+ } \
55
+ } \
56
+ } while (0)
57
+
58
+
59
+ #define MARK(FOR) \
60
+ do { \
61
+ FOR##_mark = p; \
62
+ } while (0)
63
+
64
+ #define CALLBACK(FOR) \
65
+ do { \
66
+ if (FOR##_mark) { \
67
+ if (settings->on_##FOR) { \
68
+ if (0 != settings->on_##FOR(parser, \
69
+ FOR##_mark, \
70
+ p - FOR##_mark)) \
71
+ { \
72
+ SET_ERRNO(HPE_CB_##FOR); \
73
+ return (p - data); \
74
+ } \
75
+ } \
76
+ FOR##_mark = NULL; \
77
+ } \
78
+ } while (0)
79
+
80
+
81
+ #define PROXY_CONNECTION "proxy-connection"
82
+ #define CONNECTION "connection"
83
+ #define CONTENT_LENGTH "content-length"
84
+ #define TRANSFER_ENCODING "transfer-encoding"
85
+ #define UPGRADE "upgrade"
86
+ #define CHUNKED "chunked"
87
+ #define KEEP_ALIVE "keep-alive"
88
+ #define CLOSE "close"
89
+
90
+
91
+ static const char *method_strings[] =
92
+ { "DELETE"
93
+ , "GET"
94
+ , "HEAD"
95
+ , "POST"
96
+ , "PUT"
97
+ , "CONNECT"
98
+ , "OPTIONS"
99
+ , "TRACE"
100
+ , "COPY"
101
+ , "LOCK"
102
+ , "MKCOL"
103
+ , "MOVE"
104
+ , "PROPFIND"
105
+ , "PROPPATCH"
106
+ , "UNLOCK"
107
+ , "REPORT"
108
+ , "MKACTIVITY"
109
+ , "CHECKOUT"
110
+ , "MERGE"
111
+ , "M-SEARCH"
112
+ , "NOTIFY"
113
+ , "SUBSCRIBE"
114
+ , "UNSUBSCRIBE"
115
+ , "PATCH"
116
+ };
117
+
118
+
119
+ /* Tokens as defined by rfc 2616. Also lowercases them.
120
+ * token = 1*<any CHAR except CTLs or separators>
121
+ * separators = "(" | ")" | "<" | ">" | "@"
122
+ * | "," | ";" | ":" | "\" | <">
123
+ * | "/" | "[" | "]" | "?" | "="
124
+ * | "{" | "}" | SP | HT
125
+ */
126
+ static const char tokens[256] = {
127
+ /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
128
+ 0, 0, 0, 0, 0, 0, 0, 0,
129
+ /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
130
+ 0, 0, 0, 0, 0, 0, 0, 0,
131
+ /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
132
+ 0, 0, 0, 0, 0, 0, 0, 0,
133
+ /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
134
+ 0, 0, 0, 0, 0, 0, 0, 0,
135
+ /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
136
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
137
+ /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
138
+ 0, 0, '*', '+', 0, '-', '.', '/',
139
+ /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
140
+ '0', '1', '2', '3', '4', '5', '6', '7',
141
+ /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
142
+ '8', '9', 0, 0, 0, 0, 0, 0,
143
+ /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
144
+ 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
145
+ /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
146
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
147
+ /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
148
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
149
+ /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
150
+ 'x', 'y', 'z', 0, 0, 0, '^', '_',
151
+ /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
152
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
153
+ /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
154
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
155
+ /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
156
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
157
+ /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
158
+ 'x', 'y', 'z', 0, '|', '}', '~', 0 };
159
+
160
+
161
+ static const int8_t unhex[256] =
162
+ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
163
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
164
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
165
+ , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
166
+ ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
167
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
168
+ ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
169
+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
170
+ };
171
+
172
+
173
+ static const uint8_t normal_url_char[256] = {
174
+ /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
175
+ 0, 0, 0, 0, 0, 0, 0, 0,
176
+ /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
177
+ 0, 0, 0, 0, 0, 0, 0, 0,
178
+ /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
179
+ 0, 0, 0, 0, 0, 0, 0, 0,
180
+ /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
181
+ 0, 0, 0, 0, 0, 0, 0, 0,
182
+ /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
183
+ 0, 1, 1, 0, 1, 1, 1, 1,
184
+ /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
185
+ 1, 1, 1, 1, 1, 1, 1, 1,
186
+ /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
187
+ 1, 1, 1, 1, 1, 1, 1, 1,
188
+ /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
189
+ 1, 1, 1, 1, 1, 1, 1, 0,
190
+ /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
191
+ 1, 1, 1, 1, 1, 1, 1, 1,
192
+ /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
193
+ 1, 1, 1, 1, 1, 1, 1, 1,
194
+ /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
195
+ 1, 1, 1, 1, 1, 1, 1, 1,
196
+ /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
197
+ 1, 1, 1, 1, 1, 1, 1, 1,
198
+ /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
199
+ 1, 1, 1, 1, 1, 1, 1, 1,
200
+ /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
201
+ 1, 1, 1, 1, 1, 1, 1, 1,
202
+ /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
203
+ 1, 1, 1, 1, 1, 1, 1, 1,
204
+ /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
205
+ 1, 1, 1, 1, 1, 1, 1, 0, };
206
+
207
+
208
+ enum state
209
+ { s_dead = 1 /* important that this is > 0 */
210
+
211
+ , s_start_req_or_res
212
+ , s_res_or_resp_H
213
+ , s_start_res
214
+ , s_res_H
215
+ , s_res_HT
216
+ , s_res_HTT
217
+ , s_res_HTTP
218
+ , s_res_first_http_major
219
+ , s_res_http_major
220
+ , s_res_first_http_minor
221
+ , s_res_http_minor
222
+ , s_res_first_status_code
223
+ , s_res_status_code
224
+ , s_res_status
225
+ , s_res_line_almost_done
226
+
227
+ , s_start_req
228
+
229
+ , s_req_method
230
+ , s_req_spaces_before_url
231
+ , s_req_schema
232
+ , s_req_schema_slash
233
+ , s_req_schema_slash_slash
234
+ , s_req_host
235
+ , s_req_port
236
+ , s_req_path
237
+ , s_req_query_string_start
238
+ , s_req_query_string
239
+ , s_req_fragment_start
240
+ , s_req_fragment
241
+ , s_req_http_start
242
+ , s_req_http_H
243
+ , s_req_http_HT
244
+ , s_req_http_HTT
245
+ , s_req_http_HTTP
246
+ , s_req_first_http_major
247
+ , s_req_http_major
248
+ , s_req_first_http_minor
249
+ , s_req_http_minor
250
+ , s_req_line_almost_done
251
+
252
+ , s_header_field_start
253
+ , s_header_field
254
+ , s_header_value_start
255
+ , s_header_value
256
+ , s_header_value_lws
257
+
258
+ , s_header_almost_done
259
+
260
+ , s_chunk_size_start
261
+ , s_chunk_size
262
+ , s_chunk_parameters
263
+ , s_chunk_size_almost_done
264
+
265
+ , s_headers_almost_done
266
+ /* Important: 's_headers_almost_done' must be the last 'header' state. All
267
+ * states beyond this must be 'body' states. It is used for overflow
268
+ * checking. See the PARSING_HEADER() macro.
269
+ */
270
+
271
+ , s_chunk_data
272
+ , s_chunk_data_almost_done
273
+ , s_chunk_data_done
274
+
275
+ , s_body_identity
276
+ , s_body_identity_eof
277
+ };
278
+
279
+
280
+ #define PARSING_HEADER(state) (state <= s_headers_almost_done)
281
+
282
+
283
+ enum header_states
284
+ { h_general = 0
285
+ , h_C
286
+ , h_CO
287
+ , h_CON
288
+
289
+ , h_matching_connection
290
+ , h_matching_proxy_connection
291
+ , h_matching_content_length
292
+ , h_matching_transfer_encoding
293
+ , h_matching_upgrade
294
+
295
+ , h_connection
296
+ , h_content_length
297
+ , h_transfer_encoding
298
+ , h_upgrade
299
+
300
+ , h_matching_transfer_encoding_chunked
301
+ , h_matching_connection_keep_alive
302
+ , h_matching_connection_close
303
+
304
+ , h_transfer_encoding_chunked
305
+ , h_connection_keep_alive
306
+ , h_connection_close
307
+ };
308
+
309
+
310
+ /* Macros for character classes; depends on strict-mode */
311
+ #define CR '\r'
312
+ #define LF '\n'
313
+ #define LOWER(c) (unsigned char)(c | 0x20)
314
+ #define TOKEN(c) (tokens[(unsigned char)c])
315
+ #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
316
+ #define IS_NUM(c) ((c) >= '0' && (c) <= '9')
317
+ #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
318
+
319
+ #if HTTP_PARSER_STRICT
320
+ #define IS_URL_CHAR(c) (normal_url_char[(unsigned char) (c)])
321
+ #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
322
+ #else
323
+ #define IS_URL_CHAR(c) \
324
+ (normal_url_char[(unsigned char) (c)] || ((c) & 0x80))
325
+ #define IS_HOST_CHAR(c) \
326
+ (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
327
+ #endif
328
+
329
+
330
+ #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
331
+
332
+
333
+ #if HTTP_PARSER_STRICT
334
+ # define STRICT_CHECK(cond) \
335
+ do { \
336
+ if (cond) { \
337
+ SET_ERRNO(HPE_STRICT); \
338
+ goto error; \
339
+ } \
340
+ } while (0)
341
+ # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
342
+ #else
343
+ # define STRICT_CHECK(cond)
344
+ # define NEW_MESSAGE() start_state
345
+ #endif
346
+
347
+
348
+ /* Map errno values to strings for human-readable output */
349
+ #define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
350
+ static struct {
351
+ const char *name;
352
+ const char *description;
353
+ } http_strerror_tab[] = {
354
+ HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
355
+ };
356
+ #undef HTTP_STRERROR_GEN
357
+
358
+
359
+ size_t http_parser_execute (http_parser *parser,
360
+ const http_parser_settings *settings,
361
+ const char *data,
362
+ size_t len)
363
+ {
364
+ char c, ch;
365
+ int8_t unhex_val;
366
+ const char *p = data, *pe;
367
+ size_t to_read;
368
+ enum state state;
369
+ enum header_states header_state;
370
+ size_t index = parser->index;
371
+ size_t nread = parser->nread;
372
+ const char *header_field_mark, *header_value_mark, *url_mark;
373
+ const char *matcher;
374
+
375
+ /* We're in an error state. Don't bother doing anything. */
376
+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
377
+ return 0;
378
+ }
379
+
380
+ state = (enum state) parser->state;
381
+ header_state = (enum header_states) parser->header_state;
382
+
383
+ if (len == 0) {
384
+ switch (state) {
385
+ case s_body_identity_eof:
386
+ CALLBACK2(message_complete);
387
+ return 0;
388
+
389
+ case s_dead:
390
+ case s_start_req_or_res:
391
+ case s_start_res:
392
+ case s_start_req:
393
+ return 0;
394
+
395
+ default:
396
+ SET_ERRNO(HPE_INVALID_EOF_STATE);
397
+ return 1;
398
+ }
399
+ }
400
+
401
+ /* technically we could combine all of these (except for url_mark) into one
402
+ variable, saving stack space, but it seems more clear to have them
403
+ separated. */
404
+ header_field_mark = 0;
405
+ header_value_mark = 0;
406
+ url_mark = 0;
407
+
408
+ if (state == s_header_field)
409
+ header_field_mark = data;
410
+ if (state == s_header_value)
411
+ header_value_mark = data;
412
+ if (state == s_req_path || state == s_req_schema || state == s_req_schema_slash
413
+ || state == s_req_schema_slash_slash || state == s_req_port
414
+ || state == s_req_query_string_start || state == s_req_query_string
415
+ || state == s_req_host
416
+ || state == s_req_fragment_start || state == s_req_fragment)
417
+ url_mark = data;
418
+
419
+ for (p=data, pe=data+len; p != pe; p++) {
420
+ ch = *p;
421
+
422
+ if (PARSING_HEADER(state)) {
423
+ ++nread;
424
+ /* Buffer overflow attack */
425
+ if (nread > HTTP_MAX_HEADER_SIZE) {
426
+ SET_ERRNO(HPE_HEADER_OVERFLOW);
427
+ goto error;
428
+ }
429
+ }
430
+
431
+ switch (state) {
432
+
433
+ case s_dead:
434
+ /* this state is used after a 'Connection: close' message
435
+ * the parser will error out if it reads another message
436
+ */
437
+ SET_ERRNO(HPE_CLOSED_CONNECTION);
438
+ goto error;
439
+
440
+ case s_start_req_or_res:
441
+ {
442
+ if (ch == CR || ch == LF)
443
+ break;
444
+ parser->flags = 0;
445
+ parser->content_length = -1;
446
+
447
+ CALLBACK2(message_begin);
448
+
449
+ if (ch == 'H')
450
+ state = s_res_or_resp_H;
451
+ else {
452
+ parser->type = HTTP_REQUEST;
453
+ goto start_req_method_assign;
454
+ }
455
+ break;
456
+ }
457
+
458
+ case s_res_or_resp_H:
459
+ if (ch == 'T') {
460
+ parser->type = HTTP_RESPONSE;
461
+ state = s_res_HT;
462
+ } else {
463
+ if (ch != 'E') {
464
+ SET_ERRNO(HPE_INVALID_CONSTANT);
465
+ goto error;
466
+ }
467
+
468
+ parser->type = HTTP_REQUEST;
469
+ parser->method = HTTP_HEAD;
470
+ index = 2;
471
+ state = s_req_method;
472
+ }
473
+ break;
474
+
475
+ case s_start_res:
476
+ {
477
+ parser->flags = 0;
478
+ parser->content_length = -1;
479
+
480
+ CALLBACK2(message_begin);
481
+
482
+ switch (ch) {
483
+ case 'H':
484
+ state = s_res_H;
485
+ break;
486
+
487
+ case CR:
488
+ case LF:
489
+ break;
490
+
491
+ default:
492
+ SET_ERRNO(HPE_INVALID_CONSTANT);
493
+ goto error;
494
+ }
495
+ break;
496
+ }
497
+
498
+ case s_res_H:
499
+ STRICT_CHECK(ch != 'T');
500
+ state = s_res_HT;
501
+ break;
502
+
503
+ case s_res_HT:
504
+ STRICT_CHECK(ch != 'T');
505
+ state = s_res_HTT;
506
+ break;
507
+
508
+ case s_res_HTT:
509
+ STRICT_CHECK(ch != 'P');
510
+ state = s_res_HTTP;
511
+ break;
512
+
513
+ case s_res_HTTP:
514
+ STRICT_CHECK(ch != '/');
515
+ state = s_res_first_http_major;
516
+ break;
517
+
518
+ case s_res_first_http_major:
519
+ if (ch < '1' || ch > '9') {
520
+ SET_ERRNO(HPE_INVALID_VERSION);
521
+ goto error;
522
+ }
523
+
524
+ parser->http_major = ch - '0';
525
+ state = s_res_http_major;
526
+ break;
527
+
528
+ /* major HTTP version or dot */
529
+ case s_res_http_major:
530
+ {
531
+ if (ch == '.') {
532
+ state = s_res_first_http_minor;
533
+ break;
534
+ }
535
+
536
+ if (!IS_NUM(ch)) {
537
+ SET_ERRNO(HPE_INVALID_VERSION);
538
+ goto error;
539
+ }
540
+
541
+ parser->http_major *= 10;
542
+ parser->http_major += ch - '0';
543
+
544
+ if (parser->http_major > 999) {
545
+ SET_ERRNO(HPE_INVALID_VERSION);
546
+ goto error;
547
+ }
548
+
549
+ break;
550
+ }
551
+
552
+ /* first digit of minor HTTP version */
553
+ case s_res_first_http_minor:
554
+ if (!IS_NUM(ch)) {
555
+ SET_ERRNO(HPE_INVALID_VERSION);
556
+ goto error;
557
+ }
558
+
559
+ parser->http_minor = ch - '0';
560
+ state = s_res_http_minor;
561
+ break;
562
+
563
+ /* minor HTTP version or end of request line */
564
+ case s_res_http_minor:
565
+ {
566
+ if (ch == ' ') {
567
+ state = s_res_first_status_code;
568
+ break;
569
+ }
570
+
571
+ if (!IS_NUM(ch)) {
572
+ SET_ERRNO(HPE_INVALID_VERSION);
573
+ goto error;
574
+ }
575
+
576
+ parser->http_minor *= 10;
577
+ parser->http_minor += ch - '0';
578
+
579
+ if (parser->http_minor > 999) {
580
+ SET_ERRNO(HPE_INVALID_VERSION);
581
+ goto error;
582
+ }
583
+
584
+ break;
585
+ }
586
+
587
+ case s_res_first_status_code:
588
+ {
589
+ if (!IS_NUM(ch)) {
590
+ if (ch == ' ') {
591
+ break;
592
+ }
593
+
594
+ SET_ERRNO(HPE_INVALID_STATUS);
595
+ goto error;
596
+ }
597
+ parser->status_code = ch - '0';
598
+ state = s_res_status_code;
599
+ break;
600
+ }
601
+
602
+ case s_res_status_code:
603
+ {
604
+ if (!IS_NUM(ch)) {
605
+ switch (ch) {
606
+ case ' ':
607
+ state = s_res_status;
608
+ break;
609
+ case CR:
610
+ state = s_res_line_almost_done;
611
+ break;
612
+ case LF:
613
+ state = s_header_field_start;
614
+ break;
615
+ default:
616
+ SET_ERRNO(HPE_INVALID_STATUS);
617
+ goto error;
618
+ }
619
+ break;
620
+ }
621
+
622
+ parser->status_code *= 10;
623
+ parser->status_code += ch - '0';
624
+
625
+ if (parser->status_code > 999) {
626
+ SET_ERRNO(HPE_INVALID_STATUS);
627
+ goto error;
628
+ }
629
+
630
+ break;
631
+ }
632
+
633
+ case s_res_status:
634
+ /* the human readable status. e.g. "NOT FOUND"
635
+ * we are not humans so just ignore this */
636
+ if (ch == CR) {
637
+ state = s_res_line_almost_done;
638
+ break;
639
+ }
640
+
641
+ if (ch == LF) {
642
+ state = s_header_field_start;
643
+ break;
644
+ }
645
+ break;
646
+
647
+ case s_res_line_almost_done:
648
+ STRICT_CHECK(ch != LF);
649
+ state = s_header_field_start;
650
+ break;
651
+
652
+ case s_start_req:
653
+ {
654
+ if (ch == CR || ch == LF)
655
+ break;
656
+ parser->flags = 0;
657
+ parser->content_length = -1;
658
+
659
+ CALLBACK2(message_begin);
660
+
661
+ if (!IS_ALPHA(ch)) {
662
+ SET_ERRNO(HPE_INVALID_METHOD);
663
+ goto error;
664
+ }
665
+
666
+ start_req_method_assign:
667
+ parser->method = (enum http_method) 0;
668
+ index = 1;
669
+ switch (ch) {
670
+ case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
671
+ case 'D': parser->method = HTTP_DELETE; break;
672
+ case 'G': parser->method = HTTP_GET; break;
673
+ case 'H': parser->method = HTTP_HEAD; break;
674
+ case 'L': parser->method = HTTP_LOCK; break;
675
+ case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
676
+ case 'N': parser->method = HTTP_NOTIFY; break;
677
+ case 'O': parser->method = HTTP_OPTIONS; break;
678
+ case 'P': parser->method = HTTP_POST;
679
+ /* or PROPFIND or PROPPATCH or PUT or PATCH */
680
+ break;
681
+ case 'R': parser->method = HTTP_REPORT; break;
682
+ case 'S': parser->method = HTTP_SUBSCRIBE; break;
683
+ case 'T': parser->method = HTTP_TRACE; break;
684
+ case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
685
+ default:
686
+ SET_ERRNO(HPE_INVALID_METHOD);
687
+ goto error;
688
+ }
689
+ state = s_req_method;
690
+ break;
691
+ }
692
+
693
+ case s_req_method:
694
+ {
695
+ if (ch == '\0') {
696
+ SET_ERRNO(HPE_INVALID_METHOD);
697
+ goto error;
698
+ }
699
+
700
+ matcher = method_strings[parser->method];
701
+ if (ch == ' ' && matcher[index] == '\0') {
702
+ state = s_req_spaces_before_url;
703
+ } else if (ch == matcher[index]) {
704
+ ; /* nada */
705
+ } else if (parser->method == HTTP_CONNECT) {
706
+ if (index == 1 && ch == 'H') {
707
+ parser->method = HTTP_CHECKOUT;
708
+ } else if (index == 2 && ch == 'P') {
709
+ parser->method = HTTP_COPY;
710
+ } else {
711
+ goto error;
712
+ }
713
+ } else if (parser->method == HTTP_MKCOL) {
714
+ if (index == 1 && ch == 'O') {
715
+ parser->method = HTTP_MOVE;
716
+ } else if (index == 1 && ch == 'E') {
717
+ parser->method = HTTP_MERGE;
718
+ } else if (index == 1 && ch == '-') {
719
+ parser->method = HTTP_MSEARCH;
720
+ } else if (index == 2 && ch == 'A') {
721
+ parser->method = HTTP_MKACTIVITY;
722
+ } else {
723
+ goto error;
724
+ }
725
+ } else if (index == 1 && parser->method == HTTP_POST) {
726
+ if (ch == 'R') {
727
+ parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
728
+ } else if (ch == 'U') {
729
+ parser->method = HTTP_PUT;
730
+ } else if (ch == 'A') {
731
+ parser->method = HTTP_PATCH;
732
+ } else {
733
+ goto error;
734
+ }
735
+ } else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') {
736
+ parser->method = HTTP_UNSUBSCRIBE;
737
+ } else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
738
+ parser->method = HTTP_PROPPATCH;
739
+ } else {
740
+ SET_ERRNO(HPE_INVALID_METHOD);
741
+ goto error;
742
+ }
743
+
744
+ ++index;
745
+ break;
746
+ }
747
+ case s_req_spaces_before_url:
748
+ {
749
+ if (ch == ' ') break;
750
+
751
+ if (ch == '/' || ch == '*') {
752
+ MARK(url);
753
+ state = s_req_path;
754
+ break;
755
+ }
756
+
757
+ /* Proxied requests are followed by scheme of an absolute URI (alpha).
758
+ * CONNECT is followed by a hostname, which begins with alphanum.
759
+ * All other methods are followed by '/' or '*' (handled above).
760
+ */
761
+ if (IS_ALPHA(ch) || (parser->method == HTTP_CONNECT && IS_NUM(ch))) {
762
+ MARK(url);
763
+ state = (parser->method == HTTP_CONNECT) ? s_req_host : s_req_schema;
764
+ break;
765
+ }
766
+
767
+ SET_ERRNO(HPE_INVALID_URL);
768
+ goto error;
769
+ }
770
+
771
+ case s_req_schema:
772
+ {
773
+ if (IS_ALPHA(ch)) break;
774
+
775
+ if (ch == ':') {
776
+ state = s_req_schema_slash;
777
+ break;
778
+ }
779
+
780
+ SET_ERRNO(HPE_INVALID_URL);
781
+ goto error;
782
+ }
783
+
784
+ case s_req_schema_slash:
785
+ STRICT_CHECK(ch != '/');
786
+ state = s_req_schema_slash_slash;
787
+ break;
788
+
789
+ case s_req_schema_slash_slash:
790
+ STRICT_CHECK(ch != '/');
791
+ state = s_req_host;
792
+ break;
793
+
794
+ case s_req_host:
795
+ {
796
+ if (IS_HOST_CHAR(ch)) break;
797
+ switch (ch) {
798
+ case ':':
799
+ state = s_req_port;
800
+ break;
801
+ case '/':
802
+ state = s_req_path;
803
+ break;
804
+ case ' ':
805
+ /* The request line looks like:
806
+ * "GET http://foo.bar.com HTTP/1.1"
807
+ * That is, there is no path.
808
+ */
809
+ CALLBACK(url);
810
+ state = s_req_http_start;
811
+ break;
812
+ case '?':
813
+ state = s_req_query_string_start;
814
+ break;
815
+ default:
816
+ SET_ERRNO(HPE_INVALID_HOST);
817
+ goto error;
818
+ }
819
+ break;
820
+ }
821
+
822
+ case s_req_port:
823
+ {
824
+ if (IS_NUM(ch)) break;
825
+ switch (ch) {
826
+ case '/':
827
+ state = s_req_path;
828
+ break;
829
+ case ' ':
830
+ /* The request line looks like:
831
+ * "GET http://foo.bar.com:1234 HTTP/1.1"
832
+ * That is, there is no path.
833
+ */
834
+ CALLBACK(url);
835
+ state = s_req_http_start;
836
+ break;
837
+ case '?':
838
+ state = s_req_query_string_start;
839
+ break;
840
+ default:
841
+ SET_ERRNO(HPE_INVALID_PORT);
842
+ goto error;
843
+ }
844
+ break;
845
+ }
846
+
847
+ case s_req_path:
848
+ {
849
+ if (IS_URL_CHAR(ch)) break;
850
+
851
+ switch (ch) {
852
+ case ' ':
853
+ CALLBACK(url);
854
+ state = s_req_http_start;
855
+ break;
856
+ case CR:
857
+ CALLBACK(url);
858
+ parser->http_major = 0;
859
+ parser->http_minor = 9;
860
+ state = s_req_line_almost_done;
861
+ break;
862
+ case LF:
863
+ CALLBACK(url);
864
+ parser->http_major = 0;
865
+ parser->http_minor = 9;
866
+ state = s_header_field_start;
867
+ break;
868
+ case '?':
869
+ state = s_req_query_string_start;
870
+ break;
871
+ case '#':
872
+ state = s_req_fragment_start;
873
+ break;
874
+ default:
875
+ SET_ERRNO(HPE_INVALID_PATH);
876
+ goto error;
877
+ }
878
+ break;
879
+ }
880
+
881
+ case s_req_query_string_start:
882
+ {
883
+ if (IS_URL_CHAR(ch)) {
884
+ state = s_req_query_string;
885
+ break;
886
+ }
887
+
888
+ switch (ch) {
889
+ case '?':
890
+ break; /* XXX ignore extra '?' ... is this right? */
891
+ case ' ':
892
+ CALLBACK(url);
893
+ state = s_req_http_start;
894
+ break;
895
+ case CR:
896
+ CALLBACK(url);
897
+ parser->http_major = 0;
898
+ parser->http_minor = 9;
899
+ state = s_req_line_almost_done;
900
+ break;
901
+ case LF:
902
+ CALLBACK(url);
903
+ parser->http_major = 0;
904
+ parser->http_minor = 9;
905
+ state = s_header_field_start;
906
+ break;
907
+ case '#':
908
+ state = s_req_fragment_start;
909
+ break;
910
+ default:
911
+ SET_ERRNO(HPE_INVALID_QUERY_STRING);
912
+ goto error;
913
+ }
914
+ break;
915
+ }
916
+
917
+ case s_req_query_string:
918
+ {
919
+ if (IS_URL_CHAR(ch)) break;
920
+
921
+ switch (ch) {
922
+ case '?':
923
+ /* allow extra '?' in query string */
924
+ break;
925
+ case ' ':
926
+ CALLBACK(url);
927
+ state = s_req_http_start;
928
+ break;
929
+ case CR:
930
+ CALLBACK(url);
931
+ parser->http_major = 0;
932
+ parser->http_minor = 9;
933
+ state = s_req_line_almost_done;
934
+ break;
935
+ case LF:
936
+ CALLBACK(url);
937
+ parser->http_major = 0;
938
+ parser->http_minor = 9;
939
+ state = s_header_field_start;
940
+ break;
941
+ case '#':
942
+ state = s_req_fragment_start;
943
+ break;
944
+ default:
945
+ SET_ERRNO(HPE_INVALID_QUERY_STRING);
946
+ goto error;
947
+ }
948
+ break;
949
+ }
950
+
951
+ case s_req_fragment_start:
952
+ {
953
+ if (IS_URL_CHAR(ch)) {
954
+ state = s_req_fragment;
955
+ break;
956
+ }
957
+
958
+ switch (ch) {
959
+ case ' ':
960
+ CALLBACK(url);
961
+ state = s_req_http_start;
962
+ break;
963
+ case CR:
964
+ CALLBACK(url);
965
+ parser->http_major = 0;
966
+ parser->http_minor = 9;
967
+ state = s_req_line_almost_done;
968
+ break;
969
+ case LF:
970
+ CALLBACK(url);
971
+ parser->http_major = 0;
972
+ parser->http_minor = 9;
973
+ state = s_header_field_start;
974
+ break;
975
+ case '?':
976
+ state = s_req_fragment;
977
+ break;
978
+ case '#':
979
+ break;
980
+ default:
981
+ SET_ERRNO(HPE_INVALID_FRAGMENT);
982
+ goto error;
983
+ }
984
+ break;
985
+ }
986
+
987
+ case s_req_fragment:
988
+ {
989
+ if (IS_URL_CHAR(ch)) break;
990
+
991
+ switch (ch) {
992
+ case ' ':
993
+ CALLBACK(url);
994
+ state = s_req_http_start;
995
+ break;
996
+ case CR:
997
+ CALLBACK(url);
998
+ parser->http_major = 0;
999
+ parser->http_minor = 9;
1000
+ state = s_req_line_almost_done;
1001
+ break;
1002
+ case LF:
1003
+ CALLBACK(url);
1004
+ parser->http_major = 0;
1005
+ parser->http_minor = 9;
1006
+ state = s_header_field_start;
1007
+ break;
1008
+ case '?':
1009
+ case '#':
1010
+ break;
1011
+ default:
1012
+ SET_ERRNO(HPE_INVALID_FRAGMENT);
1013
+ goto error;
1014
+ }
1015
+ break;
1016
+ }
1017
+
1018
+ case s_req_http_start:
1019
+ switch (ch) {
1020
+ case 'H':
1021
+ state = s_req_http_H;
1022
+ break;
1023
+ case ' ':
1024
+ break;
1025
+ default:
1026
+ SET_ERRNO(HPE_INVALID_CONSTANT);
1027
+ goto error;
1028
+ }
1029
+ break;
1030
+
1031
+ case s_req_http_H:
1032
+ STRICT_CHECK(ch != 'T');
1033
+ state = s_req_http_HT;
1034
+ break;
1035
+
1036
+ case s_req_http_HT:
1037
+ STRICT_CHECK(ch != 'T');
1038
+ state = s_req_http_HTT;
1039
+ break;
1040
+
1041
+ case s_req_http_HTT:
1042
+ STRICT_CHECK(ch != 'P');
1043
+ state = s_req_http_HTTP;
1044
+ break;
1045
+
1046
+ case s_req_http_HTTP:
1047
+ STRICT_CHECK(ch != '/');
1048
+ state = s_req_first_http_major;
1049
+ break;
1050
+
1051
+ /* first digit of major HTTP version */
1052
+ case s_req_first_http_major:
1053
+ if (ch < '1' || ch > '9') {
1054
+ SET_ERRNO(HPE_INVALID_VERSION);
1055
+ goto error;
1056
+ }
1057
+
1058
+ parser->http_major = ch - '0';
1059
+ state = s_req_http_major;
1060
+ break;
1061
+
1062
+ /* major HTTP version or dot */
1063
+ case s_req_http_major:
1064
+ {
1065
+ if (ch == '.') {
1066
+ state = s_req_first_http_minor;
1067
+ break;
1068
+ }
1069
+
1070
+ if (!IS_NUM(ch)) {
1071
+ SET_ERRNO(HPE_INVALID_VERSION);
1072
+ goto error;
1073
+ }
1074
+
1075
+ parser->http_major *= 10;
1076
+ parser->http_major += ch - '0';
1077
+
1078
+ if (parser->http_major > 999) {
1079
+ SET_ERRNO(HPE_INVALID_VERSION);
1080
+ goto error;
1081
+ }
1082
+
1083
+ break;
1084
+ }
1085
+
1086
+ /* first digit of minor HTTP version */
1087
+ case s_req_first_http_minor:
1088
+ if (!IS_NUM(ch)) {
1089
+ SET_ERRNO(HPE_INVALID_VERSION);
1090
+ goto error;
1091
+ }
1092
+
1093
+ parser->http_minor = ch - '0';
1094
+ state = s_req_http_minor;
1095
+ break;
1096
+
1097
+ /* minor HTTP version or end of request line */
1098
+ case s_req_http_minor:
1099
+ {
1100
+ if (ch == CR) {
1101
+ state = s_req_line_almost_done;
1102
+ break;
1103
+ }
1104
+
1105
+ if (ch == LF) {
1106
+ state = s_header_field_start;
1107
+ break;
1108
+ }
1109
+
1110
+ /* XXX allow spaces after digit? */
1111
+
1112
+ if (!IS_NUM(ch)) {
1113
+ SET_ERRNO(HPE_INVALID_VERSION);
1114
+ goto error;
1115
+ }
1116
+
1117
+ parser->http_minor *= 10;
1118
+ parser->http_minor += ch - '0';
1119
+
1120
+ if (parser->http_minor > 999) {
1121
+ SET_ERRNO(HPE_INVALID_VERSION);
1122
+ goto error;
1123
+ }
1124
+
1125
+ break;
1126
+ }
1127
+
1128
+ /* end of request line */
1129
+ case s_req_line_almost_done:
1130
+ {
1131
+ if (ch != LF) {
1132
+ SET_ERRNO(HPE_LF_EXPECTED);
1133
+ goto error;
1134
+ }
1135
+
1136
+ state = s_header_field_start;
1137
+ break;
1138
+ }
1139
+
1140
+ case s_header_field_start:
1141
+ header_field_start:
1142
+ {
1143
+ if (ch == CR) {
1144
+ state = s_headers_almost_done;
1145
+ break;
1146
+ }
1147
+
1148
+ if (ch == LF) {
1149
+ /* they might be just sending \n instead of \r\n so this would be
1150
+ * the second \n to denote the end of headers*/
1151
+ state = s_headers_almost_done;
1152
+ goto headers_almost_done;
1153
+ }
1154
+
1155
+ c = TOKEN(ch);
1156
+
1157
+ if (!c) {
1158
+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1159
+ goto error;
1160
+ }
1161
+
1162
+ MARK(header_field);
1163
+
1164
+ index = 0;
1165
+ state = s_header_field;
1166
+
1167
+ switch (c) {
1168
+ case 'c':
1169
+ header_state = h_C;
1170
+ break;
1171
+
1172
+ case 'p':
1173
+ header_state = h_matching_proxy_connection;
1174
+ break;
1175
+
1176
+ case 't':
1177
+ header_state = h_matching_transfer_encoding;
1178
+ break;
1179
+
1180
+ case 'u':
1181
+ header_state = h_matching_upgrade;
1182
+ break;
1183
+
1184
+ default:
1185
+ header_state = h_general;
1186
+ break;
1187
+ }
1188
+ break;
1189
+ }
1190
+
1191
+ case s_header_field:
1192
+ {
1193
+ c = TOKEN(ch);
1194
+
1195
+ if (c) {
1196
+ switch (header_state) {
1197
+ case h_general:
1198
+ break;
1199
+
1200
+ case h_C:
1201
+ index++;
1202
+ header_state = (c == 'o' ? h_CO : h_general);
1203
+ break;
1204
+
1205
+ case h_CO:
1206
+ index++;
1207
+ header_state = (c == 'n' ? h_CON : h_general);
1208
+ break;
1209
+
1210
+ case h_CON:
1211
+ index++;
1212
+ switch (c) {
1213
+ case 'n':
1214
+ header_state = h_matching_connection;
1215
+ break;
1216
+ case 't':
1217
+ header_state = h_matching_content_length;
1218
+ break;
1219
+ default:
1220
+ header_state = h_general;
1221
+ break;
1222
+ }
1223
+ break;
1224
+
1225
+ /* connection */
1226
+
1227
+ case h_matching_connection:
1228
+ index++;
1229
+ if (index > sizeof(CONNECTION)-1
1230
+ || c != CONNECTION[index]) {
1231
+ header_state = h_general;
1232
+ } else if (index == sizeof(CONNECTION)-2) {
1233
+ header_state = h_connection;
1234
+ }
1235
+ break;
1236
+
1237
+ /* proxy-connection */
1238
+
1239
+ case h_matching_proxy_connection:
1240
+ index++;
1241
+ if (index > sizeof(PROXY_CONNECTION)-1
1242
+ || c != PROXY_CONNECTION[index]) {
1243
+ header_state = h_general;
1244
+ } else if (index == sizeof(PROXY_CONNECTION)-2) {
1245
+ header_state = h_connection;
1246
+ }
1247
+ break;
1248
+
1249
+ /* content-length */
1250
+
1251
+ case h_matching_content_length:
1252
+ index++;
1253
+ if (index > sizeof(CONTENT_LENGTH)-1
1254
+ || c != CONTENT_LENGTH[index]) {
1255
+ header_state = h_general;
1256
+ } else if (index == sizeof(CONTENT_LENGTH)-2) {
1257
+ header_state = h_content_length;
1258
+ }
1259
+ break;
1260
+
1261
+ /* transfer-encoding */
1262
+
1263
+ case h_matching_transfer_encoding:
1264
+ index++;
1265
+ if (index > sizeof(TRANSFER_ENCODING)-1
1266
+ || c != TRANSFER_ENCODING[index]) {
1267
+ header_state = h_general;
1268
+ } else if (index == sizeof(TRANSFER_ENCODING)-2) {
1269
+ header_state = h_transfer_encoding;
1270
+ }
1271
+ break;
1272
+
1273
+ /* upgrade */
1274
+
1275
+ case h_matching_upgrade:
1276
+ index++;
1277
+ if (index > sizeof(UPGRADE)-1
1278
+ || c != UPGRADE[index]) {
1279
+ header_state = h_general;
1280
+ } else if (index == sizeof(UPGRADE)-2) {
1281
+ header_state = h_upgrade;
1282
+ }
1283
+ break;
1284
+
1285
+ case h_connection:
1286
+ case h_content_length:
1287
+ case h_transfer_encoding:
1288
+ case h_upgrade:
1289
+ if (ch != ' ') header_state = h_general;
1290
+ break;
1291
+
1292
+ default:
1293
+ assert(0 && "Unknown header_state");
1294
+ break;
1295
+ }
1296
+ break;
1297
+ }
1298
+
1299
+ if (ch == ':') {
1300
+ CALLBACK(header_field);
1301
+ state = s_header_value_start;
1302
+ break;
1303
+ }
1304
+
1305
+ if (ch == CR) {
1306
+ state = s_header_almost_done;
1307
+ CALLBACK(header_field);
1308
+ break;
1309
+ }
1310
+
1311
+ if (ch == LF) {
1312
+ CALLBACK(header_field);
1313
+ state = s_header_field_start;
1314
+ break;
1315
+ }
1316
+
1317
+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1318
+ goto error;
1319
+ }
1320
+
1321
+ case s_header_value_start:
1322
+ {
1323
+ if (ch == ' ' || ch == '\t') break;
1324
+
1325
+ MARK(header_value);
1326
+
1327
+ state = s_header_value;
1328
+ index = 0;
1329
+
1330
+ if (ch == CR) {
1331
+ CALLBACK(header_value);
1332
+ header_state = h_general;
1333
+ state = s_header_almost_done;
1334
+ break;
1335
+ }
1336
+
1337
+ if (ch == LF) {
1338
+ CALLBACK(header_value);
1339
+ state = s_header_field_start;
1340
+ break;
1341
+ }
1342
+
1343
+ c = LOWER(ch);
1344
+
1345
+ switch (header_state) {
1346
+ case h_upgrade:
1347
+ parser->flags |= F_UPGRADE;
1348
+ header_state = h_general;
1349
+ break;
1350
+
1351
+ case h_transfer_encoding:
1352
+ /* looking for 'Transfer-Encoding: chunked' */
1353
+ if ('c' == c) {
1354
+ header_state = h_matching_transfer_encoding_chunked;
1355
+ } else {
1356
+ header_state = h_general;
1357
+ }
1358
+ break;
1359
+
1360
+ case h_content_length:
1361
+ if (!IS_NUM(ch)) {
1362
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1363
+ goto error;
1364
+ }
1365
+
1366
+ parser->content_length = ch - '0';
1367
+ break;
1368
+
1369
+ case h_connection:
1370
+ /* looking for 'Connection: keep-alive' */
1371
+ if (c == 'k') {
1372
+ header_state = h_matching_connection_keep_alive;
1373
+ /* looking for 'Connection: close' */
1374
+ } else if (c == 'c') {
1375
+ header_state = h_matching_connection_close;
1376
+ } else {
1377
+ header_state = h_general;
1378
+ }
1379
+ break;
1380
+
1381
+ default:
1382
+ header_state = h_general;
1383
+ break;
1384
+ }
1385
+ break;
1386
+ }
1387
+
1388
+ case s_header_value:
1389
+ {
1390
+
1391
+ if (ch == CR) {
1392
+ CALLBACK(header_value);
1393
+ state = s_header_almost_done;
1394
+ break;
1395
+ }
1396
+
1397
+ if (ch == LF) {
1398
+ CALLBACK(header_value);
1399
+ goto header_almost_done;
1400
+ }
1401
+
1402
+ c = LOWER(ch);
1403
+
1404
+ switch (header_state) {
1405
+ case h_general:
1406
+ break;
1407
+
1408
+ case h_connection:
1409
+ case h_transfer_encoding:
1410
+ assert(0 && "Shouldn't get here.");
1411
+ break;
1412
+
1413
+ case h_content_length:
1414
+ if (ch == ' ') break;
1415
+ if (!IS_NUM(ch)) {
1416
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1417
+ goto error;
1418
+ }
1419
+
1420
+ parser->content_length *= 10;
1421
+ parser->content_length += ch - '0';
1422
+ break;
1423
+
1424
+ /* Transfer-Encoding: chunked */
1425
+ case h_matching_transfer_encoding_chunked:
1426
+ index++;
1427
+ if (index > sizeof(CHUNKED)-1
1428
+ || c != CHUNKED[index]) {
1429
+ header_state = h_general;
1430
+ } else if (index == sizeof(CHUNKED)-2) {
1431
+ header_state = h_transfer_encoding_chunked;
1432
+ }
1433
+ break;
1434
+
1435
+ /* looking for 'Connection: keep-alive' */
1436
+ case h_matching_connection_keep_alive:
1437
+ index++;
1438
+ if (index > sizeof(KEEP_ALIVE)-1
1439
+ || c != KEEP_ALIVE[index]) {
1440
+ header_state = h_general;
1441
+ } else if (index == sizeof(KEEP_ALIVE)-2) {
1442
+ header_state = h_connection_keep_alive;
1443
+ }
1444
+ break;
1445
+
1446
+ /* looking for 'Connection: close' */
1447
+ case h_matching_connection_close:
1448
+ index++;
1449
+ if (index > sizeof(CLOSE)-1 || c != CLOSE[index]) {
1450
+ header_state = h_general;
1451
+ } else if (index == sizeof(CLOSE)-2) {
1452
+ header_state = h_connection_close;
1453
+ }
1454
+ break;
1455
+
1456
+ case h_transfer_encoding_chunked:
1457
+ case h_connection_keep_alive:
1458
+ case h_connection_close:
1459
+ if (ch != ' ') header_state = h_general;
1460
+ break;
1461
+
1462
+ default:
1463
+ state = s_header_value;
1464
+ header_state = h_general;
1465
+ break;
1466
+ }
1467
+ break;
1468
+ }
1469
+
1470
+ case s_header_almost_done:
1471
+ header_almost_done:
1472
+ {
1473
+ STRICT_CHECK(ch != LF);
1474
+
1475
+ state = s_header_value_lws;
1476
+
1477
+ switch (header_state) {
1478
+ case h_connection_keep_alive:
1479
+ parser->flags |= F_CONNECTION_KEEP_ALIVE;
1480
+ break;
1481
+ case h_connection_close:
1482
+ parser->flags |= F_CONNECTION_CLOSE;
1483
+ break;
1484
+ case h_transfer_encoding_chunked:
1485
+ parser->flags |= F_CHUNKED;
1486
+ break;
1487
+ default:
1488
+ break;
1489
+ }
1490
+ break;
1491
+ }
1492
+
1493
+ case s_header_value_lws:
1494
+ {
1495
+ if (ch == ' ' || ch == '\t')
1496
+ state = s_header_value_start;
1497
+ else
1498
+ {
1499
+ state = s_header_field_start;
1500
+ goto header_field_start;
1501
+ }
1502
+ break;
1503
+ }
1504
+
1505
+ case s_headers_almost_done:
1506
+ headers_almost_done:
1507
+ {
1508
+ STRICT_CHECK(ch != LF);
1509
+
1510
+ if (parser->flags & F_TRAILING) {
1511
+ /* End of a chunked request */
1512
+ CALLBACK2(message_complete);
1513
+ state = NEW_MESSAGE();
1514
+ break;
1515
+ }
1516
+
1517
+ nread = 0;
1518
+
1519
+ if (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT) {
1520
+ parser->upgrade = 1;
1521
+ }
1522
+
1523
+ /* Here we call the headers_complete callback. This is somewhat
1524
+ * different than other callbacks because if the user returns 1, we
1525
+ * will interpret that as saying that this message has no body. This
1526
+ * is needed for the annoying case of recieving a response to a HEAD
1527
+ * request.
1528
+ */
1529
+ if (settings->on_headers_complete) {
1530
+ switch (settings->on_headers_complete(parser)) {
1531
+ case 0:
1532
+ break;
1533
+
1534
+ case 1:
1535
+ parser->flags |= F_SKIPBODY;
1536
+ break;
1537
+
1538
+ default:
1539
+ parser->state = state;
1540
+ SET_ERRNO(HPE_CB_headers_complete);
1541
+ return p - data; /* Error */
1542
+ }
1543
+ }
1544
+
1545
+ /* Exit, the rest of the connect is in a different protocol. */
1546
+ if (parser->upgrade) {
1547
+ CALLBACK2(message_complete);
1548
+ return (p - data) + 1;
1549
+ }
1550
+
1551
+ if (parser->flags & F_SKIPBODY) {
1552
+ CALLBACK2(message_complete);
1553
+ state = NEW_MESSAGE();
1554
+ } else if (parser->flags & F_CHUNKED) {
1555
+ /* chunked encoding - ignore Content-Length header */
1556
+ state = s_chunk_size_start;
1557
+ } else {
1558
+ if (parser->content_length == 0) {
1559
+ /* Content-Length header given but zero: Content-Length: 0\r\n */
1560
+ CALLBACK2(message_complete);
1561
+ state = NEW_MESSAGE();
1562
+ } else if (parser->content_length > 0) {
1563
+ /* Content-Length header given and non-zero */
1564
+ state = s_body_identity;
1565
+ } else {
1566
+ if (parser->type == HTTP_REQUEST || http_should_keep_alive(parser)) {
1567
+ /* Assume content-length 0 - read the next */
1568
+ CALLBACK2(message_complete);
1569
+ state = NEW_MESSAGE();
1570
+ } else {
1571
+ /* Read body until EOF */
1572
+ state = s_body_identity_eof;
1573
+ }
1574
+ }
1575
+ }
1576
+
1577
+ break;
1578
+ }
1579
+
1580
+ case s_body_identity:
1581
+ to_read = (size_t)MIN(pe - p, parser->content_length);
1582
+ if (to_read > 0) {
1583
+ if (settings->on_body) settings->on_body(parser, p, to_read);
1584
+ p += to_read - 1;
1585
+ parser->content_length -= to_read;
1586
+ if (parser->content_length == 0) {
1587
+ CALLBACK2(message_complete);
1588
+ state = NEW_MESSAGE();
1589
+ }
1590
+ }
1591
+ break;
1592
+
1593
+ /* read until EOF */
1594
+ case s_body_identity_eof:
1595
+ to_read = pe - p;
1596
+ if (to_read > 0) {
1597
+ if (settings->on_body) settings->on_body(parser, p, to_read);
1598
+ p += to_read - 1;
1599
+ }
1600
+ break;
1601
+
1602
+ case s_chunk_size_start:
1603
+ {
1604
+ assert(nread == 1);
1605
+ assert(parser->flags & F_CHUNKED);
1606
+
1607
+ unhex_val = unhex[(unsigned char)ch];
1608
+ if (unhex_val == -1) {
1609
+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1610
+ goto error;
1611
+ }
1612
+
1613
+ parser->content_length = unhex_val;
1614
+ state = s_chunk_size;
1615
+ break;
1616
+ }
1617
+
1618
+ case s_chunk_size:
1619
+ {
1620
+ assert(parser->flags & F_CHUNKED);
1621
+
1622
+ if (ch == CR) {
1623
+ state = s_chunk_size_almost_done;
1624
+ break;
1625
+ }
1626
+
1627
+ unhex_val = unhex[(unsigned char)ch];
1628
+
1629
+ if (unhex_val == -1) {
1630
+ if (ch == ';' || ch == ' ') {
1631
+ state = s_chunk_parameters;
1632
+ break;
1633
+ }
1634
+
1635
+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1636
+ goto error;
1637
+ }
1638
+
1639
+ parser->content_length *= 16;
1640
+ parser->content_length += unhex_val;
1641
+ break;
1642
+ }
1643
+
1644
+ case s_chunk_parameters:
1645
+ {
1646
+ assert(parser->flags & F_CHUNKED);
1647
+ /* just ignore this shit. TODO check for overflow */
1648
+ if (ch == CR) {
1649
+ state = s_chunk_size_almost_done;
1650
+ break;
1651
+ }
1652
+ break;
1653
+ }
1654
+
1655
+ case s_chunk_size_almost_done:
1656
+ {
1657
+ assert(parser->flags & F_CHUNKED);
1658
+ STRICT_CHECK(ch != LF);
1659
+
1660
+ nread = 0;
1661
+
1662
+ if (parser->content_length == 0) {
1663
+ parser->flags |= F_TRAILING;
1664
+ state = s_header_field_start;
1665
+ } else {
1666
+ state = s_chunk_data;
1667
+ }
1668
+ break;
1669
+ }
1670
+
1671
+ case s_chunk_data:
1672
+ {
1673
+ assert(parser->flags & F_CHUNKED);
1674
+
1675
+ to_read = (size_t)MIN(pe - p, parser->content_length);
1676
+
1677
+ if (to_read > 0) {
1678
+ if (settings->on_body) settings->on_body(parser, p, to_read);
1679
+ p += to_read - 1;
1680
+ }
1681
+
1682
+ if ((signed)to_read == parser->content_length) {
1683
+ state = s_chunk_data_almost_done;
1684
+ }
1685
+
1686
+ parser->content_length -= to_read;
1687
+ break;
1688
+ }
1689
+
1690
+ case s_chunk_data_almost_done:
1691
+ assert(parser->flags & F_CHUNKED);
1692
+ STRICT_CHECK(ch != CR);
1693
+ state = s_chunk_data_done;
1694
+ break;
1695
+
1696
+ case s_chunk_data_done:
1697
+ assert(parser->flags & F_CHUNKED);
1698
+ STRICT_CHECK(ch != LF);
1699
+ state = s_chunk_size_start;
1700
+ break;
1701
+
1702
+ default:
1703
+ assert(0 && "unhandled state");
1704
+ SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
1705
+ goto error;
1706
+ }
1707
+ }
1708
+
1709
+ CALLBACK(header_field);
1710
+ CALLBACK(header_value);
1711
+ CALLBACK(url);
1712
+
1713
+ parser->state = state;
1714
+ parser->header_state = header_state;
1715
+ parser->index = (unsigned char) index;
1716
+ parser->nread = nread;
1717
+
1718
+ return len;
1719
+
1720
+ error:
1721
+ if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
1722
+ SET_ERRNO(HPE_UNKNOWN);
1723
+ }
1724
+
1725
+ return (p - data);
1726
+ }
1727
+
1728
+
1729
+ int
1730
+ http_should_keep_alive (http_parser *parser)
1731
+ {
1732
+ if (parser->http_major > 0 && parser->http_minor > 0) {
1733
+ /* HTTP/1.1 */
1734
+ if (parser->flags & F_CONNECTION_CLOSE) {
1735
+ return 0;
1736
+ } else {
1737
+ return 1;
1738
+ }
1739
+ } else {
1740
+ /* HTTP/1.0 or earlier */
1741
+ if (parser->flags & F_CONNECTION_KEEP_ALIVE) {
1742
+ return 1;
1743
+ } else {
1744
+ return 0;
1745
+ }
1746
+ }
1747
+ }
1748
+
1749
+
1750
+ const char * http_method_str (enum http_method m)
1751
+ {
1752
+ return method_strings[m];
1753
+ }
1754
+
1755
+
1756
+ void
1757
+ http_parser_init (http_parser *parser, enum http_parser_type t)
1758
+ {
1759
+ parser->type = t;
1760
+ parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
1761
+ parser->nread = 0;
1762
+ parser->upgrade = 0;
1763
+ parser->flags = 0;
1764
+ parser->method = 0;
1765
+ parser->http_errno = 0;
1766
+ }
1767
+
1768
+ const char *
1769
+ http_errno_name(enum http_errno err) {
1770
+ assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
1771
+ return http_strerror_tab[err].name;
1772
+ }
1773
+
1774
+ const char *
1775
+ http_errno_description(enum http_errno err) {
1776
+ assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
1777
+ return http_strerror_tab[err].description;
1778
+ }