00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028 #ifdef HAVE_STDIO_H
00029 #include <stdio.h>
00030 #endif
00031
00032 #ifdef HAVE_STDLIB_H
00033 #include <stdlib.h>
00034 #endif
00035
00036 #ifdef HAVE_STRING_H
00037 #include <string.h>
00038 #endif
00039
00040 #ifdef HAVE_ERRNO_H
00041 #include <errno.h>
00042 #endif
00043
00044 #ifdef HAVE_NETINET_IN_H
00045 #include <netinet/in.h>
00046 #endif
00047
00048 #include "nanohttp-logging.h"
00049 #include "nanohttp-error.h"
00050 #include "nanohttp-common.h"
00051 #include "nanohttp-socket.h"
00052 #include "nanohttp-stream.h"
00053
00054
00055
00056
00057
00058 static int
00059 _http_stream_is_content_length(hpair_t * header)
00060 {
00061 return hpairnode_get_ignore_case(header, HEADER_CONTENT_LENGTH) != NULL;
00062 }
00063
00064 static int
00065 _http_stream_is_chunked(hpair_t * header)
00066 {
00067 char *chunked;
00068 chunked = hpairnode_get_ignore_case(header, HEADER_TRANSFER_ENCODING);
00069 if (chunked != NULL)
00070 {
00071 if (!strcmp(chunked, TRANSFER_ENCODING_CHUNKED))
00072 {
00073 return 1;
00074 }
00075 }
00076
00077 return 0;
00078 }
00079
00083 struct http_input_stream_t *
00084 http_input_stream_new(struct hsocket_t *sock, hpair_t * header)
00085 {
00086 struct http_input_stream_t *result;
00087 char *content_length;
00088
00089 if (!(result = (struct http_input_stream_t *) malloc(sizeof(struct http_input_stream_t))))
00090 {
00091 log_error2("malloc failed (%s)", strerror(errno));
00092 return NULL;
00093 }
00094
00095 result->sock = sock;
00096 result->err = H_OK;
00097
00098
00099 hpairnode_dump_deep(header);
00100
00101 if (_http_stream_is_content_length(header))
00102 {
00103 log_verbose1("Stream transfer with 'Content-length'");
00104 content_length = hpairnode_get_ignore_case(header, HEADER_CONTENT_LENGTH);
00105 result->content_length = atoi(content_length);
00106 result->received = 0;
00107 result->type = HTTP_TRANSFER_CONTENT_LENGTH;
00108 }
00109
00110 else if (_http_stream_is_chunked(header))
00111 {
00112 log_verbose1("Stream transfer with 'chunked'");
00113 result->type = HTTP_TRANSFER_CHUNKED;
00114 result->chunk_size = -1;
00115 result->received = -1;
00116 }
00117
00118 else
00119 {
00120 log_verbose1("Stream transfer with 'Connection: close'");
00121 result->type = HTTP_TRANSFER_CONNECTION_CLOSE;
00122 result->connection_closed = 0;
00123 result->received = 0;
00124 }
00125 return result;
00126 }
00127
00133 struct http_input_stream_t *
00134 http_input_stream_new_from_file(const char *filename)
00135 {
00136 struct http_input_stream_t *result;
00137 FILE *fd;
00138
00139 if (!(fd = fopen(filename, "rb"))) {
00140
00141 log_error2("fopen failed (%s)", strerror(errno));
00142 return NULL;
00143 }
00144
00145
00146 if (!(result = (struct http_input_stream_t *) malloc(sizeof(struct http_input_stream_t))))
00147 {
00148 log_error2("malloc failed (%s)", strerror(errno));
00149 fclose(fd);
00150 return NULL;
00151 }
00152
00153 result->type = HTTP_TRANSFER_FILE;
00154 result->fd = fd;
00155 result->deleteOnExit = 0;
00156 strcpy(result->filename, filename);
00157
00158 return result;
00159 }
00160
00161 void
00162 http_input_stream_free(struct http_input_stream_t * stream)
00163 {
00164 if (stream->type == HTTP_TRANSFER_FILE && stream->fd)
00165 {
00166 fclose(stream->fd);
00167 if (stream->deleteOnExit)
00168 log_info2("Removing '%s'", stream->filename);
00169
00170 }
00171
00172 free(stream);
00173 }
00174
00175 static int
00176 _http_input_stream_is_content_length_ready(struct http_input_stream_t * stream)
00177 {
00178 return (stream->content_length > stream->received);
00179 }
00180
00181 static int
00182 _http_input_stream_is_chunked_ready(struct http_input_stream_t * stream)
00183 {
00184 return stream->chunk_size != 0;
00185 }
00186
00187 static int
00188 _http_input_stream_is_connection_closed_ready(struct http_input_stream_t * stream)
00189 {
00190 return !stream->connection_closed;
00191 }
00192
00193 static int
00194 _http_input_stream_is_file_ready(struct http_input_stream_t * stream)
00195 {
00196 return !feof(stream->fd);
00197 }
00198
00199 static int
00200 _http_input_stream_content_length_read(struct http_input_stream_t * stream, unsigned char *dest, int size)
00201 {
00202 herror_t status;
00203 int read;
00204
00205
00206 if (stream->content_length - stream->received < size)
00207 size = stream->content_length - stream->received;
00208
00209
00210 if ((status = hsocket_recv(stream->sock, dest, size, 1, &read)) != H_OK)
00211 {
00212 stream->err = status;
00213 return -1;
00214 }
00215
00216 stream->received += read;
00217 return read;
00218 }
00219
00220 static int
00221 _http_input_stream_chunked_read_chunk_size(struct http_input_stream_t * stream)
00222 {
00223 char chunk[25];
00224 int status, i = 0;
00225 int chunk_size;
00226 herror_t err;
00227
00228 while (1)
00229 {
00230 err = hsocket_recv(stream->sock, &(chunk[i]), 1, 1, &status);
00231 if (status != 1)
00232 {
00233 stream->err = herror_new("_http_input_stream_chunked_read_chunk_size",
00234 GENERAL_INVALID_PARAM,
00235 "This should never happen!");
00236 return -1;
00237 }
00238
00239 if (err != H_OK)
00240 {
00241 log_error4("[%d] %s(): %s ", herror_code(err), herror_func(err),
00242 herror_message(err));
00243
00244 stream->err = err;
00245 return -1;
00246 }
00247
00248 if (chunk[i] == '\r' || chunk[i] == ';')
00249 {
00250 chunk[i] = '\0';
00251 }
00252 else if (chunk[i] == '\n')
00253 {
00254 chunk[i] = '\0';
00255 chunk_size = strtol(chunk, (char **) NULL, 16);
00256
00257
00258 return chunk_size;
00259 }
00260
00261 if (i == 24)
00262 {
00263 stream->err =
00264 herror_new("_http_input_stream_chunked_read_chunk_size",
00265 STREAM_ERROR_NO_CHUNK_SIZE, "reached max line == %d", i);
00266 return -1;
00267 }
00268 else
00269 i++;
00270 }
00271
00272
00273 stream->err =
00274 herror_new("_http_input_stream_chunked_read_chunk_size",
00275 STREAM_ERROR_NO_CHUNK_SIZE, "reached max line == %d", i);
00276 return -1;
00277 }
00278
00279 static int
00280 _http_input_stream_chunked_read(struct http_input_stream_t * stream, unsigned char *dest,
00281 int size)
00282 {
00283 int status, counter;
00284 int remain, read = 0;
00285 char ch;
00286 herror_t err;
00287
00288 while (size > 0)
00289 {
00290 remain = stream->chunk_size - stream->received;
00291
00292 if (remain == 0 && stream->chunk_size != -1)
00293 {
00294
00295
00296 counter = 100;
00297 while (1)
00298 {
00299 if ((err = hsocket_recv(stream->sock, &ch, 1, 1, &status)) != H_OK)
00300 {
00301 stream->err = err;
00302 return -1;
00303 }
00304
00305 if (ch == '\n')
00306 {
00307 break;
00308 }
00309 if (counter-- == 0)
00310 {
00311 stream->err = herror_new("_http_input_stream_chunked_read",
00312 STREAM_ERROR_WRONG_CHUNK_SIZE,
00313 "Wrong chunk-size");
00314 return -1;
00315 }
00316 }
00317 }
00318
00319 if (remain == 0)
00320 {
00321
00322 stream->chunk_size = _http_input_stream_chunked_read_chunk_size(stream);
00323 stream->received = 0;
00324
00325 if (stream->chunk_size < 0)
00326 {
00327
00328 return stream->chunk_size;
00329 }
00330 else if (stream->chunk_size == 0)
00331 {
00332 return read;
00333 }
00334 remain = stream->chunk_size;
00335 }
00336
00337
00338 if (remain < size)
00339 {
00340
00341 if ((err = hsocket_recv(stream->sock, &(dest[read]), remain, 1, &status)) != H_OK)
00342 {
00343 stream->err = err;
00344 return -1;
00345 }
00346 if (status != remain)
00347 {
00348 stream->err = herror_new("_http_input_stream_chunked_read",
00349 GENERAL_INVALID_PARAM,
00350 "This should never happen (remain=%d)(status=%d)!",
00351 remain, status);
00352 return -1;
00353 }
00354 }
00355 else
00356 {
00357
00358 err = hsocket_recv(stream->sock, &(dest[read]), size, 1, &status);
00359 if (status != size)
00360 {
00361 stream->err = herror_new("_http_input_stream_chunked_read",
00362 GENERAL_INVALID_PARAM,
00363 "This should never happen (size=%d)(status=%d)!",
00364 size, status);
00365 return -1;
00366 }
00367 if (err != H_OK)
00368 {
00369 stream->err = err;
00370 return -1;
00371 }
00372 }
00373
00374 read += status;
00375 size -= status;
00376 stream->received += status;
00377 }
00378
00379 return read;
00380 }
00381
00382
00383 static int
00384 _http_input_stream_connection_closed_read(struct http_input_stream_t * stream, unsigned char *dest, int size)
00385 {
00386 int status;
00387 herror_t err;
00388
00389
00390 if ((err = hsocket_recv(stream->sock, dest, size, 0, &status)) != H_OK)
00391 {
00392 stream->err = err;
00393 return -1;
00394 }
00395
00396 if (status == 0)
00397 stream->connection_closed = 1;
00398
00399 stream->received += status;
00400 return status;
00401 }
00402
00403 static int
00404 _http_input_stream_file_read(struct http_input_stream_t * stream, unsigned char *dest, int size)
00405 {
00406 size_t len;
00407
00408 if ((len = fread(dest, 1, size, stream->fd)) == -1)
00409 {
00410 stream->err = herror_new("_http_input_stream_file_read",
00411 HSOCKET_ERROR_RECEIVE, "fread() returned -1");
00412 return -1;
00413 }
00414
00415 return len;
00416 }
00417
00421 int
00422 http_input_stream_is_ready(struct http_input_stream_t * stream)
00423 {
00424
00425 if (stream == NULL)
00426 return 0;
00427
00428
00429 stream->err = H_OK;
00430
00431 switch (stream->type)
00432 {
00433 case HTTP_TRANSFER_CONTENT_LENGTH:
00434 return _http_input_stream_is_content_length_ready(stream);
00435 case HTTP_TRANSFER_CHUNKED:
00436 return _http_input_stream_is_chunked_ready(stream);
00437 case HTTP_TRANSFER_CONNECTION_CLOSE:
00438 return _http_input_stream_is_connection_closed_ready(stream);
00439 case HTTP_TRANSFER_FILE:
00440 return _http_input_stream_is_file_ready(stream);
00441 default:
00442 return 0;
00443 }
00444
00445 }
00446
00451 int
00452 http_input_stream_read(struct http_input_stream_t * stream, unsigned char *dest, int size)
00453 {
00454 int len = 0;
00455
00456 if (stream == NULL)
00457 {
00458 return -1;
00459 }
00460
00461
00462 stream->err = H_OK;
00463
00464 switch (stream->type)
00465 {
00466 case HTTP_TRANSFER_CONTENT_LENGTH:
00467 len = _http_input_stream_content_length_read(stream, dest, size);
00468 break;
00469 case HTTP_TRANSFER_CHUNKED:
00470 len = _http_input_stream_chunked_read(stream, dest, size);
00471 break;
00472 case HTTP_TRANSFER_CONNECTION_CLOSE:
00473 len = _http_input_stream_connection_closed_read(stream, dest, size);
00474 break;
00475 case HTTP_TRANSFER_FILE:
00476 len = _http_input_stream_file_read(stream, dest, size);
00477 break;
00478 default:
00479 stream->err = herror_new("http_input_stream_read",
00480 STREAM_ERROR_INVALID_TYPE,
00481 "%d is invalid stream type", stream->type);
00482 return -1;
00483 }
00484
00485 return len;
00486 }
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00502 struct http_output_stream_t *
00503 http_output_stream_new(struct hsocket_t *sock, hpair_t * header)
00504 {
00505 struct http_output_stream_t *result;
00506 char *content_length;
00507
00508
00509
00510
00511
00512
00513 if (!(result = (struct http_output_stream_t *) malloc(sizeof(struct http_output_stream_t))))
00514 {
00515 log_error2("malloc failed (%s)", strerror(errno));
00516 return NULL;
00517 }
00518
00519 result->sock = sock;
00520 result->sent = 0;
00521
00522
00523
00524
00525 if (_http_stream_is_content_length(header))
00526 {
00527 log_verbose1("Stream transfer with 'Content-length'");
00528 content_length = hpairnode_get_ignore_case(header, HEADER_CONTENT_LENGTH);
00529 result->content_length = atoi(content_length);
00530 result->type = HTTP_TRANSFER_CONTENT_LENGTH;
00531 }
00532
00533 else if (_http_stream_is_chunked(header))
00534 {
00535 log_verbose1("Stream transfer with 'chunked'");
00536 result->type = HTTP_TRANSFER_CHUNKED;
00537 }
00538
00539 else
00540 {
00541 log_verbose1("Stream transfer with 'Connection: close'");
00542 result->type = HTTP_TRANSFER_CONNECTION_CLOSE;
00543 }
00544
00545 return result;
00546 }
00547
00551 void
00552 http_output_stream_free(struct http_output_stream_t * stream)
00553 {
00554 free(stream);
00555
00556 return;
00557 }
00558
00563 herror_t
00564 http_output_stream_write(struct http_output_stream_t * stream,
00565 const unsigned char *bytes, int size)
00566 {
00567 herror_t status;
00568 char chunked[15];
00569
00570 if (stream->type == HTTP_TRANSFER_CHUNKED)
00571 {
00572 sprintf(chunked, "%x\r\n", size);
00573 if ((status = hsocket_send_string(stream->sock, chunked)) != H_OK)
00574 return status;
00575 }
00576
00577 if (size > 0)
00578 {
00579 if ((status = hsocket_send(stream->sock, bytes, size)) != H_OK)
00580 return status;
00581 }
00582
00583 if (stream->type == HTTP_TRANSFER_CHUNKED)
00584 {
00585 if ((status = hsocket_send_string(stream->sock, "\r\n")) != H_OK)
00586 return status;
00587 }
00588
00589 return H_OK;
00590 }
00591
00596 herror_t
00597 http_output_stream_write_string(struct http_output_stream_t * stream,
00598 const char *str)
00599 {
00600 return http_output_stream_write(stream, str, strlen(str));
00601 }
00602
00603
00604 herror_t
00605 http_output_stream_flush(struct http_output_stream_t * stream)
00606 {
00607 herror_t status;
00608
00609 if (stream->type == HTTP_TRANSFER_CHUNKED)
00610 {
00611 if ((status = hsocket_send_string(stream->sock, "0\r\n\r\n")) != H_OK)
00612 return status;
00613 }
00614
00615 return H_OK;
00616 }