PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/boa-0.94.14rc21/src/pipe.c

#
C | 366 lines | 243 code | 48 blank | 75 comment | 111 complexity | faf538ec3962683ef66a0497030e2a56 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * Boa, an http server
  3. * Based on code Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
  4. * Copyright (C) 1997-2004 Jon Nelson <jnelson@boa.org>
  5. * Copyright (C) 1997-2005 Larry Doolittle <ldoolitt@boa.org>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 1, or (at your option)
  10. * any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. *
  21. */
  22. /* $Id: pipe.c,v 1.39.2.16 2005/02/22 14:13:03 jnelson Exp $*/
  23. #include "boa.h"
  24. /*
  25. * Name: read_from_pipe
  26. * Description: Reads data from a pipe
  27. *
  28. * Return values:
  29. * -1: request blocked, move to blocked queue
  30. * 0: EOF or error, close it down
  31. * 1: successful read, recycle in ready queue
  32. */
  33. int read_from_pipe(request * req)
  34. {
  35. int bytes_read; /* signed */
  36. unsigned int bytes_to_read; /* unsigned */
  37. bytes_to_read = BUFFER_SIZE - (req->header_end - req->buffer - 1);
  38. if (bytes_to_read == 0) { /* buffer full */
  39. if (req->cgi_status == CGI_PARSE) { /* got+parsed header */
  40. req->cgi_status = CGI_BUFFER;
  41. *req->header_end = '\0'; /* points to end of read data */
  42. /* Could the above statement overwrite data???
  43. No, because req->header_end points to where new data
  44. should begin, not where old data is.
  45. */
  46. return process_cgi_header(req); /* cgi_status will change */
  47. }
  48. req->status = PIPE_WRITE;
  49. return 1;
  50. }
  51. bytes_read = read(req->data_fd, req->header_end, bytes_to_read);
  52. #ifdef FASCIST_LOGGING
  53. if (bytes_read > 0) {
  54. *(req->header_end + bytes_read) = '\0';
  55. fprintf(stderr, "pipe.c - read %d bytes: \"%s\"\n",
  56. bytes_read, req->header_end);
  57. } else
  58. fprintf(stderr, "pipe.c - read %d bytes\n", bytes_read);
  59. fprintf(stderr, "status, cgi_status: %d, %d\n", req->status,
  60. req->cgi_status);
  61. #endif
  62. if (bytes_read == -1) {
  63. if (errno == EINTR)
  64. return 1;
  65. else if (errno == EWOULDBLOCK || errno == EAGAIN)
  66. return -1; /* request blocked at the pipe level, but keep going */
  67. else {
  68. req->status = DEAD;
  69. log_error_doc(req);
  70. perror("pipe read");
  71. return 0;
  72. }
  73. }
  74. *(req->header_end + bytes_read) = '\0';
  75. if (bytes_read == 0) { /* eof, write rest of buffer */
  76. req->status = PIPE_WRITE;
  77. if (req->cgi_status == CGI_PARSE) { /* hasn't processed header yet */
  78. req->cgi_status = CGI_DONE;
  79. *req->header_end = '\0'; /* points to end of read data */
  80. return process_cgi_header(req); /* cgi_status will change */
  81. }
  82. req->cgi_status = CGI_DONE;
  83. return 1;
  84. }
  85. req->header_end += bytes_read;
  86. if (req->cgi_status != CGI_PARSE)
  87. return write_from_pipe(req); /* why not try and flush the buffer now? */
  88. else {
  89. char *c, *buf;
  90. buf = req->header_line;
  91. c = strstr(buf, "\n\r\n");
  92. if (c == NULL) {
  93. c = strstr(buf, "\n\n");
  94. if (c == NULL) {
  95. return 1;
  96. }
  97. }
  98. req->cgi_status = CGI_DONE;
  99. *req->header_end = '\0'; /* points to end of read data */
  100. return process_cgi_header(req); /* cgi_status will change */
  101. }
  102. return 1;
  103. }
  104. /*
  105. * Name: write_from_pipe
  106. * Description: Writes data previously read from a pipe
  107. *
  108. * Return values:
  109. * -1: request blocked, move to blocked queue
  110. * 0: EOF or error, close it down
  111. * 1: successful write, recycle in ready queue
  112. */
  113. int write_from_pipe(request * req)
  114. {
  115. int bytes_written;
  116. size_t bytes_to_write = req->header_end - req->header_line;
  117. if (bytes_to_write == 0) {
  118. if (req->cgi_status == CGI_DONE)
  119. return 0;
  120. req->status = PIPE_READ;
  121. req->header_end = req->header_line = req->buffer;
  122. return 1;
  123. }
  124. bytes_written = write(req->fd, req->header_line, bytes_to_write);
  125. if (bytes_written == -1) {
  126. if (errno == EWOULDBLOCK || errno == EAGAIN)
  127. return -1; /* request blocked at the pipe level, but keep going */
  128. else if (errno == EINTR)
  129. return 1;
  130. else {
  131. req->status = DEAD;
  132. log_error_doc(req);
  133. perror("pipe write");
  134. return 0;
  135. }
  136. }
  137. req->header_line += bytes_written;
  138. req->bytes_written += bytes_written;
  139. /* if there won't be anything to write next time, switch state */
  140. if ((unsigned) bytes_written == bytes_to_write) {
  141. req->status = PIPE_READ;
  142. req->header_end = req->header_line = req->buffer;
  143. }
  144. return 1;
  145. }
  146. #ifdef HAVE_SENDFILE
  147. int io_shuffle_sendfile(request * req)
  148. {
  149. int bytes_written;
  150. size_t bytes_to_write;
  151. off_t sendfile_offset;
  152. if (req->method == M_HEAD) {
  153. return complete_response(req);
  154. }
  155. /* XXX trouble if range is exactly 4G on a 32-bit machine? */
  156. bytes_to_write = (req->ranges->stop - req->ranges->start) + 1;
  157. if (bytes_to_write > system_bufsize)
  158. bytes_to_write = system_bufsize;
  159. retrysendfile:
  160. if (bytes_to_write == 0) {
  161. /* shouldn't get here, but... */
  162. bytes_written = 0;
  163. } else {
  164. /* arg 3 of sendfile should have type "off_t *"
  165. * struct range element start has type "unsigned long"
  166. * Where POSIX got the idea that an offset into a file
  167. * should be signed, I'll never know.
  168. */
  169. sendfile_offset = req->ranges->start;
  170. if (sendfile_offset < 0) {
  171. req->status = DEAD;
  172. log_error_doc(req);
  173. fprintf(stderr, "impossible offset (%lu) requested of sendfile\n",
  174. req->ranges->start);
  175. return 0;
  176. }
  177. bytes_written = sendfile(req->fd, req->data_fd,
  178. &sendfile_offset,
  179. bytes_to_write);
  180. if (sendfile_offset < 0) {
  181. req->status = DEAD;
  182. log_error_doc(req);
  183. fprintf(stderr,
  184. "bad craziness in sendfile offset, returned %ld\n",
  185. (long) sendfile_offset);
  186. return 0;
  187. }
  188. req->ranges->start = sendfile_offset;
  189. if (bytes_written < 0) {
  190. if (errno == EWOULDBLOCK || errno == EAGAIN) {
  191. return -1; /* request blocked at the pipe level, but keep going */
  192. } else if (errno == EINTR) {
  193. goto retrysendfile;
  194. } else {
  195. req->status = DEAD;
  196. #ifdef QUIET_DISCONNECT
  197. if (0)
  198. #else
  199. if (errno != EPIPE && errno != ECONNRESET)
  200. #endif
  201. {
  202. log_error_doc(req);
  203. perror("sendfile write");
  204. }
  205. }
  206. return 0;
  207. } else if (bytes_written == 0) {
  208. /* not sure how to handle this.
  209. * For now, treat it like it is blocked.
  210. */
  211. return -1;
  212. }/* bytes_written */
  213. } /* bytes_to_write */
  214. /* sendfile automatically updates req->ranges->start
  215. * don't touch!
  216. * req->ranges->start += bytes_written;
  217. */
  218. req->bytes_written += bytes_written;
  219. if (req->ranges->stop + 1 <= req->ranges->start) {
  220. return complete_response(req);
  221. }
  222. return 1;
  223. }
  224. #endif
  225. /* always try to read unless data_fs is 0 (and there is space)
  226. * then try to write
  227. *
  228. * Return values:
  229. * -1: request blocked, move to blocked queue
  230. * 0: EOF or error, close it down
  231. * 1: successful read, recycle in ready queue
  232. */
  233. int io_shuffle(request * req)
  234. {
  235. int bytes_to_read;
  236. int bytes_written, bytes_to_write;
  237. if (req->method == M_HEAD) {
  238. return complete_response(req);
  239. }
  240. /* FIXME: This function doesn't take into account req->filesize
  241. * when *reading* into the buffer. Grr.
  242. * June 09, 2004: jdn, I don't think it's a problem anymore,
  243. * because the ranges are verified against the filesize,
  244. * and we cap bytes_to_read at bytes_to_write.
  245. */
  246. bytes_to_read = BUFFER_SIZE - req->buffer_end - 256;
  247. bytes_to_write = (req->ranges->stop - req->ranges->start) + 1;
  248. if (bytes_to_read > bytes_to_write)
  249. bytes_to_read = bytes_to_write;
  250. if (bytes_to_read > 0 && req->data_fd) {
  251. int bytes_read;
  252. off_t temp;
  253. temp = lseek(req->data_fd, req->ranges->start, SEEK_SET);
  254. if (temp < 0) {
  255. req->status = DEAD;
  256. log_error_doc(req);
  257. perror("ioshuffle lseek");
  258. return 0;
  259. }
  260. restartread:
  261. bytes_read =
  262. read(req->data_fd, req->buffer + req->buffer_end,
  263. bytes_to_read);
  264. if (bytes_read == -1) {
  265. if (errno == EINTR)
  266. goto restartread;
  267. else if (errno == EWOULDBLOCK || errno == EAGAIN) {
  268. /* not a fatal error, don't worry about it */
  269. /* buffer is empty, we're blocking on read! */
  270. if (req->buffer_end - req->buffer_start == 0)
  271. return -1;
  272. } else {
  273. req->status = DEAD;
  274. log_error_doc(req);
  275. perror("ioshuffle read");
  276. return 0;
  277. }
  278. } else if (bytes_read == 0) { /* eof, write rest of buffer */
  279. close(req->data_fd);
  280. req->data_fd = 0;
  281. } else {
  282. req->buffer_end += bytes_read;
  283. req->ranges->start += bytes_read;
  284. if ((req->ranges->stop + 1 - req->ranges->start) == 0) {
  285. return complete_response(req);
  286. }
  287. }
  288. }
  289. bytes_to_write = req->buffer_end - req->buffer_start;
  290. if (bytes_to_write == 0) {
  291. if (req->data_fd == 0)
  292. return 0; /* done */
  293. req->buffer_end = req->buffer_start = 0;
  294. return 1;
  295. }
  296. restartwrite:
  297. bytes_written =
  298. write(req->fd, req->buffer + req->buffer_start, bytes_to_write);
  299. if (bytes_written == -1) {
  300. if (errno == EWOULDBLOCK || errno == EAGAIN)
  301. return -1; /* request blocked at the pipe level, but keep going */
  302. else if (errno == EINTR)
  303. goto restartwrite;
  304. else {
  305. req->status = DEAD;
  306. log_error_doc(req);
  307. perror("ioshuffle write");
  308. return 0;
  309. }
  310. } else if (bytes_written == 0) {
  311. }
  312. req->buffer_start += bytes_written;
  313. req->bytes_written += bytes_written;
  314. if (bytes_to_write == bytes_written) {
  315. req->buffer_end = req->buffer_start = 0;
  316. }
  317. return 1;
  318. }