Skip to content

Commit 251d5c8

Browse files
committed
Merge remote-tracking branch 'kiwanami/master'
2 parents a6d71ca + 138a6b6 commit 251d5c8

File tree

2 files changed

+266
-27
lines changed

2 files changed

+266
-27
lines changed

config

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
ngx_addon_name=ngx_http_gridfs_module
22
HTTP_MODULES="$HTTP_MODULES ngx_http_gridfs_module"
3+
4+
case "$NGX_PLATFORM" in
5+
Linux:*)
6+
/bin/cp -f $ngx_addon_dir/mongo-c-driver/src/platform/linux/net.* $ngx_addon_dir/mongo-c-driver/src/
7+
;;
8+
esac
9+
310
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_gridfs_module.c $ngx_addon_dir/mongo-c-driver/src/*.c"
411
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/mongo-c-driver/src/*.h"
512
CFLAGS="$CFLAGS -Wno-unused-function -Wno-missing-field-initializers -D_MONGO_USE_GETADDRINFO -D_POSIX_C_SOURCE=200112L --std=c99 -Isrc"

ngx_http_gridfs_module.c

Lines changed: 259 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -557,10 +557,10 @@ static ngx_int_t ngx_http_gridfs_init_worker(ngx_cycle_t* cycle) {
557557

558558
for (i = 0; i < gridfs_main_conf->loc_confs.nelts; i++) {
559559
if (ngx_http_mongo_add_connection(cycle, gridfs_loc_confs[i]) == NGX_ERROR) {
560-
return NGX_ERROR;
560+
return NGX_OK;
561561
}
562562
if (ngx_http_mongo_authenticate(cycle->log, gridfs_loc_confs[i]) == NGX_ERROR) {
563-
return NGX_ERROR;
563+
return NGX_OK;
564564
}
565565
}
566566

@@ -667,6 +667,139 @@ static int url_decode(char * filename) {
667667
return 1;
668668
}
669669

670+
static void gridfs_parse_range(ngx_http_request_t* r, ngx_str_t* range_str, uint64_t* range_start, uint64_t* range_end, gridfs_offset content_length) {
671+
u_char *p, *last;
672+
off_t start, end, len;
673+
ngx_uint_t suffix, bad;
674+
enum {
675+
sw_start = 0,
676+
sw_first_byte_pos,
677+
sw_first_byte_pos_n,
678+
sw_last_byte_pos,
679+
sw_last_byte_pos_n,
680+
sw_done
681+
} state = 0;
682+
683+
p = (u_char *) ngx_strnstr(range_str->data, "bytes=", range_str->len);
684+
685+
if (p == NULL) {
686+
return;
687+
}
688+
689+
p += sizeof("bytes=") - 1;
690+
last = range_str->data + range_str->len;
691+
692+
/*
693+
* bytes= contain ranges compatible with RFC 2616, "14.35.1 Byte Ranges",
694+
* but no whitespaces permitted
695+
*/
696+
697+
bad = 0;
698+
len = 0;
699+
suffix = 0;
700+
start = 0;
701+
end = 0;
702+
703+
while (p < last) {
704+
705+
switch (state) {
706+
707+
case sw_start:
708+
case sw_first_byte_pos:
709+
if (*p == '-') {
710+
p++;
711+
suffix = 1;
712+
state = sw_last_byte_pos;
713+
break;
714+
}
715+
start = 0;
716+
state = sw_first_byte_pos_n;
717+
718+
/* fall through */
719+
720+
case sw_first_byte_pos_n:
721+
if (*p == '-') {
722+
p++;
723+
state = sw_last_byte_pos;
724+
break;
725+
}
726+
if (*p < '0' || *p > '9') {
727+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
728+
"bytes header filter: unexpected char '%c'"
729+
" (expected first-byte-pos)", *p);
730+
bad = 1;
731+
break;
732+
}
733+
start = start * 10 + *p - '0';
734+
p++;
735+
break;
736+
737+
case sw_last_byte_pos:
738+
if (*p == ',' || *p == '&' || *p == ';') {
739+
/* no last byte pos, assume end of file */
740+
end = content_length - 1;
741+
state = sw_done;
742+
break;
743+
}
744+
end = 0;
745+
state = sw_last_byte_pos_n;
746+
747+
/* fall though */
748+
749+
case sw_last_byte_pos_n:
750+
if (*p == ',' || *p == '&' || *p == ';') {
751+
state = sw_done;
752+
break;
753+
}
754+
if (*p < '0' || *p > '9') {
755+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
756+
"bytes header filter: unexpected char '%c'"
757+
" (expected last-byte-pos)", *p);
758+
bad = 1;
759+
break;
760+
}
761+
end = end * 10 + *p - '0';
762+
p++;
763+
break;
764+
765+
case sw_done:
766+
*range_start = start;
767+
*range_end = end;
768+
769+
break;
770+
}
771+
772+
if (bad) {
773+
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
774+
"bytes header filter: invalid range specification");
775+
return;
776+
}
777+
}
778+
779+
switch (state) {
780+
781+
case sw_last_byte_pos:
782+
end = content_length - 1;
783+
784+
case sw_last_byte_pos_n:
785+
if (start > end) {
786+
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
787+
"bytes header filter: invalid range specification");
788+
return;
789+
}
790+
791+
*range_start = start;
792+
*range_end = end;
793+
break;
794+
795+
default:
796+
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
797+
"bytes header filter: invalid range specification");
798+
return;
799+
800+
}
801+
}
802+
670803
static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
671804
ngx_http_gridfs_loc_conf_t* gridfs_conf;
672805
ngx_http_core_loc_conf_t* core_conf;
@@ -698,6 +831,9 @@ static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
698831
int status;
699832
volatile ngx_uint_t e = FALSE;
700833
volatile ngx_uint_t ecounter = 0;
834+
uint64_t range_start = 0;
835+
uint64_t range_end = 0;
836+
uint64_t current_buf_pos = 0;
701837

702838
gridfs_conf = ngx_http_get_module_loc_conf(request, ngx_http_gridfs_module);
703839
core_conf = ngx_http_get_module_loc_conf(request, ngx_http_core_module);
@@ -711,13 +847,19 @@ static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
711847
return NGX_HTTP_INTERNAL_SERVER_ERROR;
712848
}
713849

714-
if ( !(&mongo_conn->conn.connected)
715-
&& (ngx_http_mongo_reconnect(request->connection->log, mongo_conn) == NGX_ERROR
716-
|| ngx_http_mongo_reauth(request->connection->log, mongo_conn) == NGX_ERROR)) {
717-
ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
718-
"Could not connect to mongo: \"%V\"", &gridfs_conf->mongo);
719-
if(&mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); }
720-
return NGX_HTTP_SERVICE_UNAVAILABLE;
850+
if (mongo_conn->conn.connected == 0) {
851+
if (ngx_http_mongo_reconnect(request->connection->log, mongo_conn) == NGX_ERROR) {
852+
ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
853+
"Could not connect to mongo: \"%V\"", &gridfs_conf->mongo);
854+
if(mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); }
855+
return NGX_HTTP_SERVICE_UNAVAILABLE;
856+
}
857+
if (ngx_http_mongo_reauth(request->connection->log, mongo_conn) == NGX_ERROR) {
858+
ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
859+
"Failed to reauth to mongo: \"%V\"", &gridfs_conf->mongo);
860+
if(mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); }
861+
return NGX_HTTP_SERVICE_UNAVAILABLE;
862+
}
721863
}
722864

723865
// ---------- RETRIEVE KEY ---------- //
@@ -751,17 +893,18 @@ static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
751893

752894
do {
753895
e = FALSE;
754-
if (gridfs_init(&mongo_conn->conn,
755-
(const char*)gridfs_conf->db.data,
756-
(const char*)gridfs_conf->root_collection.data,
757-
&gfs) != MONGO_OK) {
896+
status = gridfs_init(&mongo_conn->conn,
897+
(const char*)gridfs_conf->db.data,
898+
(const char*)gridfs_conf->root_collection.data,
899+
&gfs);
900+
if (status != MONGO_OK) {
758901
e = TRUE; ecounter++;
759902
if (ecounter > MONGO_MAX_RETRIES_PER_REQUEST
760903
|| ngx_http_mongo_reconnect(request->connection->log, mongo_conn) == NGX_ERROR
761904
|| ngx_http_mongo_reauth(request->connection->log, mongo_conn) == NGX_ERROR) {
762905
ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
763906
"Mongo connection dropped, could not reconnect");
764-
if(&mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); }
907+
if(mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); }
765908
free(value);
766909
return NGX_HTTP_SERVICE_UNAVAILABLE;
767910
}
@@ -796,15 +939,65 @@ static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
796939
/* Get information about the file */
797940
length = gridfile_get_contentlength(&gfile);
798941
numchunks = gridfile_get_numchunks(&gfile);
942+
943+
// NaN workaround
944+
if (numchunks > INT_MAX)
945+
{
946+
gridfile_destroy(&gfile);
947+
gridfs_destroy(&gfs);
948+
return NGX_HTTP_NOT_FOUND;
949+
}
950+
799951
contenttype = (char*)gridfile_get_contenttype(&gfile);
800952

801953
md5 = (char*)gridfile_get_md5(&gfile);
802954
last_modified = gridfile_get_uploaddate(&gfile);
803955

956+
// ---------- Partial Range
957+
// set follow-fork-mode child
958+
// attach (pid)
959+
// break ngx_http_gridfs_module.c:959
960+
961+
if (request->headers_in.range) {
962+
gridfs_parse_range(request, &request->headers_in.range->value, &range_start, &range_end, length);
963+
}
964+
804965
// ---------- SEND THE HEADERS ---------- //
805966

806-
request->headers_out.status = NGX_HTTP_OK;
807-
request->headers_out.content_length_n = length;
967+
if (range_start == 0 && range_end == 0) {
968+
request->headers_out.status = NGX_HTTP_OK;
969+
request->headers_out.content_length_n = length;
970+
} else {
971+
request->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
972+
request->headers_out.content_length_n = length;
973+
//request->headers_out.content_range = range_end - range_start + 1;
974+
975+
ngx_table_elt_t *content_range;
976+
977+
content_range = ngx_list_push(&request->headers_out.headers);
978+
if (content_range == NULL) {
979+
return NGX_ERROR;
980+
}
981+
982+
request->headers_out.content_range = content_range;
983+
984+
content_range->hash = 1;
985+
ngx_str_set(&content_range->key, "Content-Range");
986+
987+
content_range->value.data = ngx_pnalloc(request->pool,sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN);
988+
if (content_range->value.data == NULL) {
989+
return NGX_ERROR;
990+
}
991+
992+
/* "Content-Range: bytes SSSS-EEEE/TTTT" header */
993+
content_range->value.len = ngx_sprintf(content_range->value.data,
994+
"bytes %O-%O/%O",
995+
range_start, range_end,
996+
request->headers_out.content_length_n)
997+
- content_range->value.data;
998+
999+
request->headers_out.content_length_n = range_end - range_start + 1;
1000+
}
8081001
if (contenttype != NULL) {
8091002
request->headers_out.content_type.len = strlen(contenttype);
8101003
request->headers_out.content_type.data = (u_char*)contenttype;
@@ -920,7 +1113,7 @@ static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
9201113
|| ngx_http_mongo_reauth(request->connection->log, mongo_conn) == NGX_ERROR) {
9211114
ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
9221115
"Mongo connection dropped, could not reconnect");
923-
if(&mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); }
1116+
if(mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); }
9241117
gridfile_destroy(&gfile);
9251118
gridfs_destroy(&gfs);
9261119
return NGX_HTTP_SERVICE_UNAVAILABLE;
@@ -930,19 +1123,58 @@ static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
9301123

9311124
chunk = cursors[i]->current;
9321125
bson_find(&it, &chunk, "data");
933-
chunk_len = bson_iterator_bin_len( &it );
1126+
chunk_len = bson_iterator_bin_len( &it ); // break ngx_http_gridfs_module.c:1099
9341127
chunk_data = bson_iterator_bin_data( &it );
9351128

936-
/* Set up the buffer chain */
937-
buffer->pos = (u_char*)chunk_data;
938-
buffer->last = (u_char*)chunk_data + chunk_len;
939-
buffer->memory = 1;
940-
buffer->last_buf = (i == numchunks-1);
941-
out.buf = buffer;
942-
out.next = NULL;
1129+
if (range_start == 0 && range_end == 0) {
1130+
/* <<no range request>> */
1131+
/* Set up the buffer chain */
1132+
buffer->pos = (u_char*)chunk_data;
1133+
buffer->last = (u_char*)chunk_data + chunk_len;
1134+
buffer->memory = 1;
1135+
buffer->last_buf = (i == numchunks-1);
1136+
out.buf = buffer;
1137+
out.next = NULL;
1138+
1139+
/* Serve the Chunk */
1140+
rc = ngx_http_output_filter(request, &out);
1141+
} else {
1142+
/* <<range request>> */
1143+
if ( range_start >= (current_buf_pos+chunk_len) ||
1144+
range_end <= current_buf_pos) {
1145+
/* no output */
1146+
ngx_pfree(request->pool, buffer);
1147+
} else {
1148+
if (range_start <= current_buf_pos) {
1149+
buffer->pos = (u_char*)chunk_data;
1150+
} else {
1151+
buffer->pos = (u_char*)chunk_data + (range_start - current_buf_pos);
1152+
}
1153+
if (range_end < (current_buf_pos+chunk_len)) {
1154+
buffer->last = (u_char*)chunk_data + (range_end - current_buf_pos + 1);
1155+
} else {
1156+
buffer->last = (u_char*)chunk_data + chunk_len;
1157+
}
1158+
if (buffer->pos == buffer->last) {
1159+
ngx_log_error(NGX_LOG_ALERT, request->connection->log, 0,
1160+
"zero size buf in writer "
1161+
"range_start:%d range_end:%d "
1162+
"current_buf_pos:%d chunk_len:%d i:%d numchunk:%d",
1163+
range_start,range_end,
1164+
current_buf_pos, chunk_len,
1165+
i,numchunks);
1166+
}
1167+
buffer->memory = 1;
1168+
buffer->last_buf = (i == numchunks-1) || (range_end < (current_buf_pos+chunk_len));
1169+
out.buf = buffer;
1170+
out.next = NULL;
1171+
1172+
/* Serve the Chunk */
1173+
rc = ngx_http_output_filter(request, &out);
1174+
}
1175+
}
9431176

944-
/* Serve the Chunk */
945-
rc = ngx_http_output_filter(request, &out);
1177+
current_buf_pos += chunk_len;
9461178

9471179
/* TODO: More Codes to Catch? */
9481180
if (rc == NGX_ERROR) {

0 commit comments

Comments
 (0)