THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

796 lines
19KB

  1. #include "cache.h"
  2. #include "config.h"
  3. #include "repository.h"
  4. #include "refs.h"
  5. #include "pkt-line.h"
  6. #include "object.h"
  7. #include "tag.h"
  8. #include "exec-cmd.h"
  9. #include "run-command.h"
  10. #include "string-list.h"
  11. #include "url.h"
  12. #include "argv-array.h"
  13. #include "packfile.h"
  14. #include "object-store.h"
  15. #include "protocol.h"
  16. static const char content_type[] = "Content-Type";
  17. static const char content_length[] = "Content-Length";
  18. static const char last_modified[] = "Last-Modified";
  19. static int getanyfile = 1;
  20. static unsigned long max_request_buffer = 10 * 1024 * 1024;
  21. static struct string_list *query_params;
  22. struct rpc_service {
  23. const char *name;
  24. const char *config_name;
  25. unsigned buffer_input : 1;
  26. signed enabled : 2;
  27. };
  28. static struct rpc_service rpc_service[] = {
  29. { "upload-pack", "uploadpack", 1, 1 },
  30. { "receive-pack", "receivepack", 0, -1 },
  31. };
  32. static struct string_list *get_parameters(void)
  33. {
  34. if (!query_params) {
  35. const char *query = getenv("QUERY_STRING");
  36. query_params = xcalloc(1, sizeof(*query_params));
  37. while (query && *query) {
  38. char *name = url_decode_parameter_name(&query);
  39. char *value = url_decode_parameter_value(&query);
  40. struct string_list_item *i;
  41. i = string_list_lookup(query_params, name);
  42. if (!i)
  43. i = string_list_insert(query_params, name);
  44. else
  45. free(i->util);
  46. i->util = value;
  47. }
  48. }
  49. return query_params;
  50. }
  51. static const char *get_parameter(const char *name)
  52. {
  53. struct string_list_item *i;
  54. i = string_list_lookup(get_parameters(), name);
  55. return i ? i->util : NULL;
  56. }
  57. __attribute__((format (printf, 2, 3)))
  58. static void format_write(int fd, const char *fmt, ...)
  59. {
  60. static char buffer[1024];
  61. va_list args;
  62. unsigned n;
  63. va_start(args, fmt);
  64. n = vsnprintf(buffer, sizeof(buffer), fmt, args);
  65. va_end(args);
  66. if (n >= sizeof(buffer))
  67. die("protocol error: impossibly long line");
  68. write_or_die(fd, buffer, n);
  69. }
  70. static void http_status(struct strbuf *hdr, unsigned code, const char *msg)
  71. {
  72. strbuf_addf(hdr, "Status: %u %s\r\n", code, msg);
  73. }
  74. static void hdr_str(struct strbuf *hdr, const char *name, const char *value)
  75. {
  76. strbuf_addf(hdr, "%s: %s\r\n", name, value);
  77. }
  78. static void hdr_int(struct strbuf *hdr, const char *name, uintmax_t value)
  79. {
  80. strbuf_addf(hdr, "%s: %" PRIuMAX "\r\n", name, value);
  81. }
  82. static void hdr_date(struct strbuf *hdr, const char *name, timestamp_t when)
  83. {
  84. const char *value = show_date(when, 0, DATE_MODE(RFC2822));
  85. hdr_str(hdr, name, value);
  86. }
  87. static void hdr_nocache(struct strbuf *hdr)
  88. {
  89. hdr_str(hdr, "Expires", "Fri, 01 Jan 1980 00:00:00 GMT");
  90. hdr_str(hdr, "Pragma", "no-cache");
  91. hdr_str(hdr, "Cache-Control", "no-cache, max-age=0, must-revalidate");
  92. }
  93. static void hdr_cache_forever(struct strbuf *hdr)
  94. {
  95. timestamp_t now = time(NULL);
  96. hdr_date(hdr, "Date", now);
  97. hdr_date(hdr, "Expires", now + 31536000);
  98. hdr_str(hdr, "Cache-Control", "public, max-age=31536000");
  99. }
  100. static void end_headers(struct strbuf *hdr)
  101. {
  102. strbuf_add(hdr, "\r\n", 2);
  103. write_or_die(1, hdr->buf, hdr->len);
  104. strbuf_release(hdr);
  105. }
  106. __attribute__((format (printf, 2, 3)))
  107. static NORETURN void not_found(struct strbuf *hdr, const char *err, ...)
  108. {
  109. va_list params;
  110. http_status(hdr, 404, "Not Found");
  111. hdr_nocache(hdr);
  112. end_headers(hdr);
  113. va_start(params, err);
  114. if (err && *err)
  115. vfprintf(stderr, err, params);
  116. va_end(params);
  117. exit(0);
  118. }
  119. __attribute__((format (printf, 2, 3)))
  120. static NORETURN void forbidden(struct strbuf *hdr, const char *err, ...)
  121. {
  122. va_list params;
  123. http_status(hdr, 403, "Forbidden");
  124. hdr_nocache(hdr);
  125. end_headers(hdr);
  126. va_start(params, err);
  127. if (err && *err)
  128. vfprintf(stderr, err, params);
  129. va_end(params);
  130. exit(0);
  131. }
  132. static void select_getanyfile(struct strbuf *hdr)
  133. {
  134. if (!getanyfile)
  135. forbidden(hdr, "Unsupported service: getanyfile");
  136. }
  137. static void send_strbuf(struct strbuf *hdr,
  138. const char *type, struct strbuf *buf)
  139. {
  140. hdr_int(hdr, content_length, buf->len);
  141. hdr_str(hdr, content_type, type);
  142. end_headers(hdr);
  143. write_or_die(1, buf->buf, buf->len);
  144. }
  145. static void send_local_file(struct strbuf *hdr, const char *the_type,
  146. const char *name)
  147. {
  148. char *p = git_pathdup("%s", name);
  149. size_t buf_alloc = 8192;
  150. char *buf = xmalloc(buf_alloc);
  151. int fd;
  152. struct stat sb;
  153. fd = open(p, O_RDONLY);
  154. if (fd < 0)
  155. not_found(hdr, "Cannot open '%s': %s", p, strerror(errno));
  156. if (fstat(fd, &sb) < 0)
  157. die_errno("Cannot stat '%s'", p);
  158. hdr_int(hdr, content_length, sb.st_size);
  159. hdr_str(hdr, content_type, the_type);
  160. hdr_date(hdr, last_modified, sb.st_mtime);
  161. end_headers(hdr);
  162. for (;;) {
  163. ssize_t n = xread(fd, buf, buf_alloc);
  164. if (n < 0)
  165. die_errno("Cannot read '%s'", p);
  166. if (!n)
  167. break;
  168. write_or_die(1, buf, n);
  169. }
  170. close(fd);
  171. free(buf);
  172. free(p);
  173. }
  174. static void get_text_file(struct strbuf *hdr, char *name)
  175. {
  176. select_getanyfile(hdr);
  177. hdr_nocache(hdr);
  178. send_local_file(hdr, "text/plain", name);
  179. }
  180. static void get_loose_object(struct strbuf *hdr, char *name)
  181. {
  182. select_getanyfile(hdr);
  183. hdr_cache_forever(hdr);
  184. send_local_file(hdr, "application/x-git-loose-object", name);
  185. }
  186. static void get_pack_file(struct strbuf *hdr, char *name)
  187. {
  188. select_getanyfile(hdr);
  189. hdr_cache_forever(hdr);
  190. send_local_file(hdr, "application/x-git-packed-objects", name);
  191. }
  192. static void get_idx_file(struct strbuf *hdr, char *name)
  193. {
  194. select_getanyfile(hdr);
  195. hdr_cache_forever(hdr);
  196. send_local_file(hdr, "application/x-git-packed-objects-toc", name);
  197. }
  198. static void http_config(void)
  199. {
  200. int i, value = 0;
  201. struct strbuf var = STRBUF_INIT;
  202. git_config_get_bool("http.getanyfile", &getanyfile);
  203. git_config_get_ulong("http.maxrequestbuffer", &max_request_buffer);
  204. for (i = 0; i < ARRAY_SIZE(rpc_service); i++) {
  205. struct rpc_service *svc = &rpc_service[i];
  206. strbuf_addf(&var, "http.%s", svc->config_name);
  207. if (!git_config_get_bool(var.buf, &value))
  208. svc->enabled = value;
  209. strbuf_reset(&var);
  210. }
  211. strbuf_release(&var);
  212. }
  213. static struct rpc_service *select_service(struct strbuf *hdr, const char *name)
  214. {
  215. const char *svc_name;
  216. struct rpc_service *svc = NULL;
  217. int i;
  218. if (!skip_prefix(name, "git-", &svc_name))
  219. forbidden(hdr, "Unsupported service: '%s'", name);
  220. for (i = 0; i < ARRAY_SIZE(rpc_service); i++) {
  221. struct rpc_service *s = &rpc_service[i];
  222. if (!strcmp(s->name, svc_name)) {
  223. svc = s;
  224. break;
  225. }
  226. }
  227. if (!svc)
  228. forbidden(hdr, "Unsupported service: '%s'", name);
  229. if (svc->enabled < 0) {
  230. const char *user = getenv("REMOTE_USER");
  231. svc->enabled = (user && *user) ? 1 : 0;
  232. }
  233. if (!svc->enabled)
  234. forbidden(hdr, "Service not enabled: '%s'", svc->name);
  235. return svc;
  236. }
  237. static void write_to_child(int out, const unsigned char *buf, ssize_t len, const char *prog_name)
  238. {
  239. if (write_in_full(out, buf, len) < 0)
  240. die("unable to write to '%s'", prog_name);
  241. }
  242. /*
  243. * This is basically strbuf_read(), except that if we
  244. * hit max_request_buffer we die (we'd rather reject a
  245. * maliciously large request than chew up infinite memory).
  246. */
  247. static ssize_t read_request_eof(int fd, unsigned char **out)
  248. {
  249. size_t len = 0, alloc = 8192;
  250. unsigned char *buf = xmalloc(alloc);
  251. if (max_request_buffer < alloc)
  252. max_request_buffer = alloc;
  253. while (1) {
  254. ssize_t cnt;
  255. cnt = read_in_full(fd, buf + len, alloc - len);
  256. if (cnt < 0) {
  257. free(buf);
  258. return -1;
  259. }
  260. /* partial read from read_in_full means we hit EOF */
  261. len += cnt;
  262. if (len < alloc) {
  263. *out = buf;
  264. return len;
  265. }
  266. /* otherwise, grow and try again (if we can) */
  267. if (alloc == max_request_buffer)
  268. die("request was larger than our maximum size (%lu);"
  269. " try setting GIT_HTTP_MAX_REQUEST_BUFFER",
  270. max_request_buffer);
  271. alloc = alloc_nr(alloc);
  272. if (alloc > max_request_buffer)
  273. alloc = max_request_buffer;
  274. REALLOC_ARRAY(buf, alloc);
  275. }
  276. }
  277. static ssize_t read_request_fixed_len(int fd, ssize_t req_len, unsigned char **out)
  278. {
  279. unsigned char *buf = NULL;
  280. ssize_t cnt = 0;
  281. if (max_request_buffer < req_len) {
  282. die("request was larger than our maximum size (%lu): "
  283. "%" PRIuMAX "; try setting GIT_HTTP_MAX_REQUEST_BUFFER",
  284. max_request_buffer, (uintmax_t)req_len);
  285. }
  286. buf = xmalloc(req_len);
  287. cnt = read_in_full(fd, buf, req_len);
  288. if (cnt < 0) {
  289. free(buf);
  290. return -1;
  291. }
  292. *out = buf;
  293. return cnt;
  294. }
  295. static ssize_t get_content_length(void)
  296. {
  297. ssize_t val = -1;
  298. const char *str = getenv("CONTENT_LENGTH");
  299. if (str && *str && !git_parse_ssize_t(str, &val))
  300. die("failed to parse CONTENT_LENGTH: %s", str);
  301. return val;
  302. }
  303. static ssize_t read_request(int fd, unsigned char **out, ssize_t req_len)
  304. {
  305. if (req_len < 0)
  306. return read_request_eof(fd, out);
  307. else
  308. return read_request_fixed_len(fd, req_len, out);
  309. }
  310. static void inflate_request(const char *prog_name, int out, int buffer_input, ssize_t req_len)
  311. {
  312. git_zstream stream;
  313. unsigned char *full_request = NULL;
  314. unsigned char in_buf[8192];
  315. unsigned char out_buf[8192];
  316. unsigned long cnt = 0;
  317. int req_len_defined = req_len >= 0;
  318. size_t req_remaining_len = req_len;
  319. memset(&stream, 0, sizeof(stream));
  320. git_inflate_init_gzip_only(&stream);
  321. while (1) {
  322. ssize_t n;
  323. if (buffer_input) {
  324. if (full_request)
  325. n = 0; /* nothing left to read */
  326. else
  327. n = read_request(0, &full_request, req_len);
  328. stream.next_in = full_request;
  329. } else {
  330. ssize_t buffer_len;
  331. if (req_len_defined && req_remaining_len <= sizeof(in_buf))
  332. buffer_len = req_remaining_len;
  333. else
  334. buffer_len = sizeof(in_buf);
  335. n = xread(0, in_buf, buffer_len);
  336. stream.next_in = in_buf;
  337. if (req_len_defined && n > 0)
  338. req_remaining_len -= n;
  339. }
  340. if (n <= 0)
  341. die("request ended in the middle of the gzip stream");
  342. stream.avail_in = n;
  343. while (0 < stream.avail_in) {
  344. int ret;
  345. stream.next_out = out_buf;
  346. stream.avail_out = sizeof(out_buf);
  347. ret = git_inflate(&stream, Z_NO_FLUSH);
  348. if (ret != Z_OK && ret != Z_STREAM_END)
  349. die("zlib error inflating request, result %d", ret);
  350. n = stream.total_out - cnt;
  351. write_to_child(out, out_buf, stream.total_out - cnt, prog_name);
  352. cnt = stream.total_out;
  353. if (ret == Z_STREAM_END)
  354. goto done;
  355. }
  356. }
  357. done:
  358. git_inflate_end(&stream);
  359. close(out);
  360. free(full_request);
  361. }
  362. static void copy_request(const char *prog_name, int out, ssize_t req_len)
  363. {
  364. unsigned char *buf;
  365. ssize_t n = read_request(0, &buf, req_len);
  366. if (n < 0)
  367. die_errno("error reading request body");
  368. write_to_child(out, buf, n, prog_name);
  369. close(out);
  370. free(buf);
  371. }
  372. static void pipe_fixed_length(const char *prog_name, int out, size_t req_len)
  373. {
  374. unsigned char buf[8192];
  375. size_t remaining_len = req_len;
  376. while (remaining_len > 0) {
  377. size_t chunk_length = remaining_len > sizeof(buf) ? sizeof(buf) : remaining_len;
  378. ssize_t n = xread(0, buf, chunk_length);
  379. if (n < 0)
  380. die_errno("Reading request failed");
  381. write_to_child(out, buf, n, prog_name);
  382. remaining_len -= n;
  383. }
  384. close(out);
  385. }
  386. static void run_service(const char **argv, int buffer_input)
  387. {
  388. const char *encoding = getenv("HTTP_CONTENT_ENCODING");
  389. const char *user = getenv("REMOTE_USER");
  390. const char *host = getenv("REMOTE_ADDR");
  391. int gzipped_request = 0;
  392. struct child_process cld = CHILD_PROCESS_INIT;
  393. ssize_t req_len = get_content_length();
  394. if (encoding && !strcmp(encoding, "gzip"))
  395. gzipped_request = 1;
  396. else if (encoding && !strcmp(encoding, "x-gzip"))
  397. gzipped_request = 1;
  398. if (!user || !*user)
  399. user = "anonymous";
  400. if (!host || !*host)
  401. host = "(none)";
  402. if (!getenv("GIT_COMMITTER_NAME"))
  403. argv_array_pushf(&cld.env_array, "GIT_COMMITTER_NAME=%s", user);
  404. if (!getenv("GIT_COMMITTER_EMAIL"))
  405. argv_array_pushf(&cld.env_array,
  406. "GIT_COMMITTER_EMAIL=%s@http.%s", user, host);
  407. cld.argv = argv;
  408. if (buffer_input || gzipped_request || req_len >= 0)
  409. cld.in = -1;
  410. cld.git_cmd = 1;
  411. cld.clean_on_exit = 1;
  412. cld.wait_after_clean = 1;
  413. if (start_command(&cld))
  414. exit(1);
  415. close(1);
  416. if (gzipped_request)
  417. inflate_request(argv[0], cld.in, buffer_input, req_len);
  418. else if (buffer_input)
  419. copy_request(argv[0], cld.in, req_len);
  420. else if (req_len >= 0)
  421. pipe_fixed_length(argv[0], cld.in, req_len);
  422. else
  423. close(0);
  424. if (finish_command(&cld))
  425. exit(1);
  426. }
  427. static int show_text_ref(const char *name, const struct object_id *oid,
  428. int flag, void *cb_data)
  429. {
  430. const char *name_nons = strip_namespace(name);
  431. struct strbuf *buf = cb_data;
  432. struct object *o = parse_object(the_repository, oid);
  433. if (!o)
  434. return 0;
  435. strbuf_addf(buf, "%s\t%s\n", oid_to_hex(oid), name_nons);
  436. if (o->type == OBJ_TAG) {
  437. o = deref_tag(the_repository, o, name, 0);
  438. if (!o)
  439. return 0;
  440. strbuf_addf(buf, "%s\t%s^{}\n", oid_to_hex(&o->oid),
  441. name_nons);
  442. }
  443. return 0;
  444. }
  445. static void get_info_refs(struct strbuf *hdr, char *arg)
  446. {
  447. const char *service_name = get_parameter("service");
  448. struct strbuf buf = STRBUF_INIT;
  449. hdr_nocache(hdr);
  450. if (service_name) {
  451. const char *argv[] = {NULL /* service name */,
  452. "--stateless-rpc", "--advertise-refs",
  453. ".", NULL};
  454. struct rpc_service *svc = select_service(hdr, service_name);
  455. strbuf_addf(&buf, "application/x-git-%s-advertisement",
  456. svc->name);
  457. hdr_str(hdr, content_type, buf.buf);
  458. end_headers(hdr);
  459. if (determine_protocol_version_server() != protocol_v2) {
  460. packet_write_fmt(1, "# service=git-%s\n", svc->name);
  461. packet_flush(1);
  462. }
  463. argv[0] = svc->name;
  464. run_service(argv, 0);
  465. } else {
  466. select_getanyfile(hdr);
  467. for_each_namespaced_ref(show_text_ref, &buf);
  468. send_strbuf(hdr, "text/plain", &buf);
  469. }
  470. strbuf_release(&buf);
  471. }
  472. static int show_head_ref(const char *refname, const struct object_id *oid,
  473. int flag, void *cb_data)
  474. {
  475. struct strbuf *buf = cb_data;
  476. if (flag & REF_ISSYMREF) {
  477. const char *target = resolve_ref_unsafe(refname,
  478. RESOLVE_REF_READING,
  479. NULL, NULL);
  480. if (target)
  481. strbuf_addf(buf, "ref: %s\n", strip_namespace(target));
  482. } else {
  483. strbuf_addf(buf, "%s\n", oid_to_hex(oid));
  484. }
  485. return 0;
  486. }
  487. static void get_head(struct strbuf *hdr, char *arg)
  488. {
  489. struct strbuf buf = STRBUF_INIT;
  490. select_getanyfile(hdr);
  491. head_ref_namespaced(show_head_ref, &buf);
  492. send_strbuf(hdr, "text/plain", &buf);
  493. strbuf_release(&buf);
  494. }
  495. static void get_info_packs(struct strbuf *hdr, char *arg)
  496. {
  497. size_t objdirlen = strlen(get_object_directory());
  498. struct strbuf buf = STRBUF_INIT;
  499. struct packed_git *p;
  500. size_t cnt = 0;
  501. select_getanyfile(hdr);
  502. for (p = get_all_packs(the_repository); p; p = p->next) {
  503. if (p->pack_local)
  504. cnt++;
  505. }
  506. strbuf_grow(&buf, cnt * 53 + 2);
  507. for (p = get_all_packs(the_repository); p; p = p->next) {
  508. if (p->pack_local)
  509. strbuf_addf(&buf, "P %s\n", p->pack_name + objdirlen + 6);
  510. }
  511. strbuf_addch(&buf, '\n');
  512. hdr_nocache(hdr);
  513. send_strbuf(hdr, "text/plain; charset=utf-8", &buf);
  514. strbuf_release(&buf);
  515. }
  516. static void check_content_type(struct strbuf *hdr, const char *accepted_type)
  517. {
  518. const char *actual_type = getenv("CONTENT_TYPE");
  519. if (!actual_type)
  520. actual_type = "";
  521. if (strcmp(actual_type, accepted_type)) {
  522. http_status(hdr, 415, "Unsupported Media Type");
  523. hdr_nocache(hdr);
  524. end_headers(hdr);
  525. format_write(1,
  526. "Expected POST with Content-Type '%s',"
  527. " but received '%s' instead.\n",
  528. accepted_type, actual_type);
  529. exit(0);
  530. }
  531. }
  532. static void service_rpc(struct strbuf *hdr, char *service_name)
  533. {
  534. const char *argv[] = {NULL, "--stateless-rpc", ".", NULL};
  535. struct rpc_service *svc = select_service(hdr, service_name);
  536. struct strbuf buf = STRBUF_INIT;
  537. strbuf_reset(&buf);
  538. strbuf_addf(&buf, "application/x-git-%s-request", svc->name);
  539. check_content_type(hdr, buf.buf);
  540. hdr_nocache(hdr);
  541. strbuf_reset(&buf);
  542. strbuf_addf(&buf, "application/x-git-%s-result", svc->name);
  543. hdr_str(hdr, content_type, buf.buf);
  544. end_headers(hdr);
  545. argv[0] = svc->name;
  546. run_service(argv, svc->buffer_input);
  547. strbuf_release(&buf);
  548. }
  549. static int dead;
  550. static NORETURN void die_webcgi(const char *err, va_list params)
  551. {
  552. if (dead <= 1) {
  553. struct strbuf hdr = STRBUF_INIT;
  554. vreportf("fatal: ", err, params);
  555. http_status(&hdr, 500, "Internal Server Error");
  556. hdr_nocache(&hdr);
  557. end_headers(&hdr);
  558. }
  559. exit(0); /* we successfully reported a failure ;-) */
  560. }
  561. static int die_webcgi_recursing(void)
  562. {
  563. return dead++ > 1;
  564. }
  565. static char* getdir(void)
  566. {
  567. struct strbuf buf = STRBUF_INIT;
  568. char *pathinfo = getenv("PATH_INFO");
  569. char *root = getenv("GIT_PROJECT_ROOT");
  570. char *path = getenv("PATH_TRANSLATED");
  571. if (root && *root) {
  572. if (!pathinfo || !*pathinfo)
  573. die("GIT_PROJECT_ROOT is set but PATH_INFO is not");
  574. if (daemon_avoid_alias(pathinfo))
  575. die("'%s': aliased", pathinfo);
  576. end_url_with_slash(&buf, root);
  577. if (pathinfo[0] == '/')
  578. pathinfo++;
  579. strbuf_addstr(&buf, pathinfo);
  580. return strbuf_detach(&buf, NULL);
  581. } else if (path && *path) {
  582. return xstrdup(path);
  583. } else
  584. die("No GIT_PROJECT_ROOT or PATH_TRANSLATED from server");
  585. return NULL;
  586. }
  587. static struct service_cmd {
  588. const char *method;
  589. const char *pattern;
  590. void (*imp)(struct strbuf *, char *);
  591. } services[] = {
  592. {"GET", "/HEAD$", get_head},
  593. {"GET", "/info/refs$", get_info_refs},
  594. {"GET", "/objects/info/alternates$", get_text_file},
  595. {"GET", "/objects/info/http-alternates$", get_text_file},
  596. {"GET", "/objects/info/packs$", get_info_packs},
  597. {"GET", "/objects/[0-9a-f]{2}/[0-9a-f]{38}$", get_loose_object},
  598. {"GET", "/objects/[0-9a-f]{2}/[0-9a-f]{62}$", get_loose_object},
  599. {"GET", "/objects/pack/pack-[0-9a-f]{40}\\.pack$", get_pack_file},
  600. {"GET", "/objects/pack/pack-[0-9a-f]{64}\\.pack$", get_pack_file},
  601. {"GET", "/objects/pack/pack-[0-9a-f]{40}\\.idx$", get_idx_file},
  602. {"GET", "/objects/pack/pack-[0-9a-f]{64}\\.idx$", get_idx_file},
  603. {"POST", "/git-upload-pack$", service_rpc},
  604. {"POST", "/git-receive-pack$", service_rpc}
  605. };
  606. static int bad_request(struct strbuf *hdr, const struct service_cmd *c)
  607. {
  608. const char *proto = getenv("SERVER_PROTOCOL");
  609. if (proto && !strcmp(proto, "HTTP/1.1")) {
  610. http_status(hdr, 405, "Method Not Allowed");
  611. hdr_str(hdr, "Allow",
  612. !strcmp(c->method, "GET") ? "GET, HEAD" : c->method);
  613. } else
  614. http_status(hdr, 400, "Bad Request");
  615. hdr_nocache(hdr);
  616. end_headers(hdr);
  617. return 0;
  618. }
  619. int cmd_main(int argc, const char **argv)
  620. {
  621. char *method = getenv("REQUEST_METHOD");
  622. char *dir;
  623. struct service_cmd *cmd = NULL;
  624. char *cmd_arg = NULL;
  625. int i;
  626. struct strbuf hdr = STRBUF_INIT;
  627. set_die_routine(die_webcgi);
  628. set_die_is_recursing_routine(die_webcgi_recursing);
  629. if (!method)
  630. die("No REQUEST_METHOD from server");
  631. if (!strcmp(method, "HEAD"))
  632. method = "GET";
  633. dir = getdir();
  634. for (i = 0; i < ARRAY_SIZE(services); i++) {
  635. struct service_cmd *c = &services[i];
  636. regex_t re;
  637. regmatch_t out[1];
  638. if (regcomp(&re, c->pattern, REG_EXTENDED))
  639. die("Bogus regex in service table: %s", c->pattern);
  640. if (!regexec(&re, dir, 1, out, 0)) {
  641. size_t n;
  642. if (strcmp(method, c->method))
  643. return bad_request(&hdr, c);
  644. cmd = c;
  645. n = out[0].rm_eo - out[0].rm_so;
  646. cmd_arg = xmemdupz(dir + out[0].rm_so + 1, n - 1);
  647. dir[out[0].rm_so] = 0;
  648. break;
  649. }
  650. regfree(&re);
  651. }
  652. if (!cmd)
  653. not_found(&hdr, "Request not supported: '%s'", dir);
  654. setup_path();
  655. if (!enter_repo(dir, 0))
  656. not_found(&hdr, "Not a git repository: '%s'", dir);
  657. if (!getenv("GIT_HTTP_EXPORT_ALL") &&
  658. access("git-daemon-export-ok", F_OK) )
  659. not_found(&hdr, "Repository not exported: '%s'", dir);
  660. http_config();
  661. max_request_buffer = git_env_ulong("GIT_HTTP_MAX_REQUEST_BUFFER",
  662. max_request_buffer);
  663. cmd->imp(&hdr, cmd_arg);
  664. return 0;
  665. }