comparison src/http/modules/ngx_http_mp4_module.c @ 6782:b123eae3fd4e

Mp4: introduced custom version of ngx_atofp(). This allows to correctly parse "start" and "end" arguments without null-termination (ticket #475), and also fixes rounding errors observed with strtod() when using i387 instructions.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 27 Oct 2016 17:57:16 +0300
parents 6136a51f9c21
children 2b2239a1e0d4
comparison
equal deleted inserted replaced
6781:ca27074f8f0f 6782:b123eae3fd4e
214 #define ngx_mp4_last_trak(mp4) \ 214 #define ngx_mp4_last_trak(mp4) \
215 &((ngx_http_mp4_trak_t *) mp4->trak.elts)[mp4->trak.nelts - 1] 215 &((ngx_http_mp4_trak_t *) mp4->trak.elts)[mp4->trak.nelts - 1]
216 216
217 217
218 static ngx_int_t ngx_http_mp4_handler(ngx_http_request_t *r); 218 static ngx_int_t ngx_http_mp4_handler(ngx_http_request_t *r);
219 static ngx_int_t ngx_http_mp4_atofp(u_char *line, size_t n, size_t point);
219 220
220 static ngx_int_t ngx_http_mp4_process(ngx_http_mp4_file_t *mp4); 221 static ngx_int_t ngx_http_mp4_process(ngx_http_mp4_file_t *mp4);
221 static ngx_int_t ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, 222 static ngx_int_t ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4,
222 ngx_http_mp4_atom_handler_t *atom, uint64_t atom_data_size); 223 ngx_http_mp4_atom_handler_t *atom, uint64_t atom_data_size);
223 static ngx_int_t ngx_http_mp4_read(ngx_http_mp4_file_t *mp4, size_t size); 224 static ngx_int_t ngx_http_mp4_read(ngx_http_mp4_file_t *mp4, size_t size);
535 536
536 if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) { 537 if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) {
537 538
538 /* 539 /*
539 * A Flash player may send start value with a lot of digits 540 * A Flash player may send start value with a lot of digits
540 * after dot so strtod() is used instead of atofp(). NaNs and 541 * after dot so a custom function is used instead of ngx_atofp().
541 * infinities become negative numbers after (int) conversion.
542 */ 542 */
543 543
544 ngx_set_errno(0); 544 start = ngx_http_mp4_atofp(value.data, value.len, 3);
545 start = (int) (strtod((char *) value.data, NULL) * 1000);
546
547 if (ngx_errno != 0) {
548 start = -1;
549 }
550 } 545 }
551 546
552 if (ngx_http_arg(r, (u_char *) "end", 3, &value) == NGX_OK) { 547 if (ngx_http_arg(r, (u_char *) "end", 3, &value) == NGX_OK) {
553 548
554 ngx_set_errno(0); 549 end = ngx_http_mp4_atofp(value.data, value.len, 3);
555 end = (int) (strtod((char *) value.data, NULL) * 1000);
556
557 if (ngx_errno != 0) {
558 end = -1;
559 }
560 550
561 if (end > 0) { 551 if (end > 0) {
562 if (start < 0) { 552 if (start < 0) {
563 start = 0; 553 start = 0;
564 } 554 }
681 671
682 out.buf = b; 672 out.buf = b;
683 out.next = NULL; 673 out.next = NULL;
684 674
685 return ngx_http_output_filter(r, &out); 675 return ngx_http_output_filter(r, &out);
676 }
677
678
679 static ngx_int_t
680 ngx_http_mp4_atofp(u_char *line, size_t n, size_t point)
681 {
682 ngx_int_t value, cutoff, cutlim;
683 ngx_uint_t dot;
684
685 /* same as ngx_atofp(), but allows additional digits */
686
687 if (n == 0) {
688 return NGX_ERROR;
689 }
690
691 cutoff = NGX_MAX_INT_T_VALUE / 10;
692 cutlim = NGX_MAX_INT_T_VALUE % 10;
693
694 dot = 0;
695
696 for (value = 0; n--; line++) {
697
698 if (*line == '.') {
699 if (dot) {
700 return NGX_ERROR;
701 }
702
703 dot = 1;
704 continue;
705 }
706
707 if (*line < '0' || *line > '9') {
708 return NGX_ERROR;
709 }
710
711 if (point == 0) {
712 continue;
713 }
714
715 if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
716 return NGX_ERROR;
717 }
718
719 value = value * 10 + (*line - '0');
720 point -= dot;
721 }
722
723 while (point--) {
724 if (value > cutoff) {
725 return NGX_ERROR;
726 }
727
728 value = value * 10;
729 }
730
731 return value;
686 } 732 }
687 733
688 734
689 static ngx_int_t 735 static ngx_int_t
690 ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) 736 ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)