cmogstored dev/user discussion/issues/patches/etc
 help / color / mirror / code / Atom feed
* [PATCH] http: return 416 errors in more cases for bad Ranges
@ 2015-11-09  5:36 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2015-11-09  5:36 UTC (permalink / raw)
  To: cmogstored-public

For completely unparseable Range: headers, we'll ignore them
entirely as nginx does.  However, if /bytes=/ is matched, we'll
start returning 416 errors instead of 400.
---
 cmogstored.h       |  3 ++-
 http_get.c         |  2 ++
 http_parser.rl     | 56 ++++++++++++++++++++++++++++++++++++------------------
 test/http_range.rb |  8 ++++++--
 4 files changed, 47 insertions(+), 22 deletions(-)

diff --git a/cmogstored.h b/cmogstored.h
index a7309b5..5aa7c01 100644
--- a/cmogstored.h
+++ b/cmogstored.h
@@ -204,9 +204,10 @@ struct mog_http {
 		unsigned has_md5:1;
 		unsigned has_content_range:1; /* for PUT */
 		unsigned has_range:1;         /* for GET */
+		unsigned bad_range:1;
 		unsigned skip_rbuf_defer:1;
 		enum mog_chunk_state chunk_state:2;
-		unsigned unused_padding:3;
+		unsigned unused_padding:2;
 		uint8_t path_tip;
 		uint8_t path_end;
 		uint16_t line_end;
diff --git a/http_get.c b/http_get.c
index bb721f1..8025093 100644
--- a/http_get.c
+++ b/http_get.c
@@ -136,6 +136,8 @@ static off_t http_get_resp_hdr(struct mog_fd *mfd, struct stat *sb)
 			offset, offset + count - 1, /* bytes M-N */
 			(long long)sb->st_size,
 			http->_p.persistent ? "keep-alive" : "close");
+	} else if (http->_p.bad_range) {
+		goto bad_range;
 	} else {
 resp_200:
 		count = (long long)sb->st_size;
diff --git a/http_parser.rl b/http_parser.rl
index 8e82828..5683b7d 100644
--- a/http_parser.rl
+++ b/http_parser.rl
@@ -21,6 +21,18 @@ static bool length_incr(off_t *len, unsigned c)
 	return false;
 }
 
+static char *skip_header(struct mog_http *http, char *buf, const char *pe)
+{
+	char *p;
+
+	assert(http->_p.line_end > 0 && "no previous request/header line");
+	assert(buf[http->_p.line_end] == '\n' && "bad http->_p.line_end");
+	p = buf + http->_p.line_end + 1;
+	assert(p <= pe && "overflow");
+
+	return p;
+}
+
 %%{
 	machine http_parser;
 	include http_common "http_common.rl";
@@ -69,20 +81,31 @@ static bool length_incr(off_t *len, unsigned c)
 			"bytes=" > {
 				http->_p.range_beg = http->_p.range_end = -1;
 			}
-			(digit*) $ {
-				if (http->_p.range_beg < 0)
-					http->_p.range_beg = 0;
-				if (!length_incr(&http->_p.range_beg, fc))
-					fbreak;
-			}
-			'-'
-			(digit*) $ {
-				if (http->_p.range_end < 0)
-					http->_p.range_end = 0;
-				if (!length_incr(&http->_p.range_end, fc))
-					fbreak;
+			(
+				(digit*) $ {
+					if (http->_p.range_beg < 0)
+						http->_p.range_beg = 0;
+					if (!length_incr(&http->_p.range_beg,
+							 fc))
+						fbreak;
+				}
+				'-'
+				(digit*) $ {
+					if (http->_p.range_end < 0)
+						http->_p.range_end = 0;
+					if (!length_incr(&http->_p.range_end,
+							 fc))
+						fbreak;
+				}
+			) $! {
+				http->_p.bad_range = 1;
+				p = skip_header(http, buf, pe);
+				fgoto ignored_header;
 			}
-                ) $! { errno = EINVAL; fbreak; }
+		) $! {
+			p = skip_header(http, buf, pe);
+			fgoto ignored_header;
+		}
 		eor @ { http->_p.has_range = 1; };
 	transfer_encoding_chunked = "Transfer-Encoding:"i sep
 		"chunked"i eor > { http->_p.chunked = 1; };
@@ -102,12 +125,7 @@ static bool length_incr(off_t *len, unsigned c)
 		  content_md5 |
 		  connection ) $!
 		{
-			assert(http->_p.line_end > 0 &&
-			       "no previous request/header line");
-			assert(buf[http->_p.line_end] == '\n' &&
-			       "bad http->_p.line_end");
-			p = buf + http->_p.line_end + 1;
-			assert(p <= pe && "overflow");
+			p = skip_header(http, buf, pe);
 			fgoto ignored_header;
 		};
 	headers = header_line* '\r''\n' > { really_done = 1; fbreak; };
diff --git a/test/http_range.rb b/test/http_range.rb
index 982d767..e19e6c5 100644
--- a/test/http_range.rb
+++ b/test/http_range.rb
@@ -161,10 +161,14 @@ class TestHTTPRange < Test::Unit::TestCase
             assert_equal nil, cm_r.body if Net::HTTP::Head === meth
           end
 
-          %w(-5-5 4qasdlkj 323).each do |bogus|
+          %w(-5-5 4qasdlkj 323 0--1).each do |bogus|
             r["Range"] = "bytes=#{bogus}"
             cm_r = cm.request(r)
-            assert_equal 400, cm_r.code.to_i, "bogus=#{bogus}"
+            assert_equal 416, cm_r.code.to_i, "bogus=#{bogus}"
+
+            r["Range"] = bogus
+            cm_r = cm.request(r)
+            assert_equal 200, cm_r.code.to_i, "no bytes=, full response"
           end
 
           r["Range"] = "bytes=5-6666"
-- 
EW


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2015-11-09  5:36 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-09  5:36 [PATCH] http: return 416 errors in more cases for bad Ranges Eric Wong

Code repositories for project(s) associated with this public inbox

	https://yhbt.net/cmogstored.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).