@@ -557,10 +557,10 @@ static ngx_int_t ngx_http_gridfs_init_worker(ngx_cycle_t* cycle) {
557
557
558
558
for (i = 0 ; i < gridfs_main_conf -> loc_confs .nelts ; i ++ ) {
559
559
if (ngx_http_mongo_add_connection (cycle , gridfs_loc_confs [i ]) == NGX_ERROR ) {
560
- return NGX_ERROR ;
560
+ return NGX_OK ;
561
561
}
562
562
if (ngx_http_mongo_authenticate (cycle -> log , gridfs_loc_confs [i ]) == NGX_ERROR ) {
563
- return NGX_ERROR ;
563
+ return NGX_OK ;
564
564
}
565
565
}
566
566
@@ -667,6 +667,139 @@ static int url_decode(char * filename) {
667
667
return 1 ;
668
668
}
669
669
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
+
670
803
static ngx_int_t ngx_http_gridfs_handler (ngx_http_request_t * request ) {
671
804
ngx_http_gridfs_loc_conf_t * gridfs_conf ;
672
805
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) {
698
831
int status ;
699
832
volatile ngx_uint_t e = FALSE;
700
833
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 ;
701
837
702
838
gridfs_conf = ngx_http_get_module_loc_conf (request , ngx_http_gridfs_module );
703
839
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) {
711
847
return NGX_HTTP_INTERNAL_SERVER_ERROR ;
712
848
}
713
849
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
+ }
721
863
}
722
864
723
865
// ---------- RETRIEVE KEY ---------- //
@@ -751,17 +893,18 @@ static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
751
893
752
894
do {
753
895
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 ) {
758
901
e = TRUE; ecounter ++ ;
759
902
if (ecounter > MONGO_MAX_RETRIES_PER_REQUEST
760
903
|| ngx_http_mongo_reconnect (request -> connection -> log , mongo_conn ) == NGX_ERROR
761
904
|| ngx_http_mongo_reauth (request -> connection -> log , mongo_conn ) == NGX_ERROR ) {
762
905
ngx_log_error (NGX_LOG_ERR , request -> connection -> log , 0 ,
763
906
"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 ); }
765
908
free (value );
766
909
return NGX_HTTP_SERVICE_UNAVAILABLE ;
767
910
}
@@ -796,15 +939,65 @@ static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
796
939
/* Get information about the file */
797
940
length = gridfile_get_contentlength (& gfile );
798
941
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
+
799
951
contenttype = (char * )gridfile_get_contenttype (& gfile );
800
952
801
953
md5 = (char * )gridfile_get_md5 (& gfile );
802
954
last_modified = gridfile_get_uploaddate (& gfile );
803
955
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
+
804
965
// ---------- SEND THE HEADERS ---------- //
805
966
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
+ }
808
1001
if (contenttype != NULL ) {
809
1002
request -> headers_out .content_type .len = strlen (contenttype );
810
1003
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) {
920
1113
|| ngx_http_mongo_reauth (request -> connection -> log , mongo_conn ) == NGX_ERROR ) {
921
1114
ngx_log_error (NGX_LOG_ERR , request -> connection -> log , 0 ,
922
1115
"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 ); }
924
1117
gridfile_destroy (& gfile );
925
1118
gridfs_destroy (& gfs );
926
1119
return NGX_HTTP_SERVICE_UNAVAILABLE ;
@@ -930,19 +1123,58 @@ static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
930
1123
931
1124
chunk = cursors [i ]-> current ;
932
1125
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
934
1127
chunk_data = bson_iterator_bin_data ( & it );
935
1128
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
+ }
943
1176
944
- /* Serve the Chunk */
945
- rc = ngx_http_output_filter (request , & out );
1177
+ current_buf_pos += chunk_len ;
946
1178
947
1179
/* TODO: More Codes to Catch? */
948
1180
if (rc == NGX_ERROR ) {
0 commit comments