parsing of headers

pull/4/head
Zlatin Balevsky 2019-05-28 16:16:29 +01:00
parent 6d3d2d94dc
commit 822e07c243
4 changed files with 188 additions and 4 deletions

View File

@ -56,7 +56,6 @@ class FileManager {
void onFileUnsharedEvent(FileUnsharedEvent e) {
SharedFile sf = e.unsharedFile
byte [] root = sf.getInfoHash().getRoot()
Set<SharedFile> existing
Set<SharedFile> existing = rootToFiles.get(root)
if (existing != null) {
existing.remove(sf)

View File

@ -1,16 +1,90 @@
package com.muwire.core.upload
import java.nio.charset.StandardCharsets
import com.muwire.core.InfoHash
import groovy.util.logging.Log
import net.i2p.data.Base64
@Log
class Request {
private static final byte R = "\r".getBytes(StandardCharsets.US_ASCII)[0]
private static final byte N = "\n".getBytes(StandardCharsets.US_ASCII)[0]
InfoHash infoHash
Range range
Map<String, String> headers
static Range parse(InfoHash infoHash, InputStream is) throws IOException {
static Request parse(InfoHash infoHash, InputStream is) throws IOException {
Map<String,String> headers = new HashMap<>()
byte [] tmp = new byte[0x1 << 14]
while(true) {
boolean r = false
boolean n = false
int idx = 0
while (true) {
byte read = is.read()
if (read == -1)
throw new IOException("Stream closed")
if (!r && read == N)
throw new IOException("Received N before R")
if (read == R) {
if (r)
throw new IOException("double R")
r = true
continue
}
if (r && !n) {
if (read != N)
throw new IOException("R not followed by N")
n = true
break
}
if (idx == 0x1 << 14)
throw new IOException("Header too long")
tmp[idx++] = read
}
if (idx == 0)
break
String header = new String(tmp, 0, idx, StandardCharsets.US_ASCII)
log.fine("Read header $header")
int keyIdx = header.indexOf(":")
if (keyIdx < 1)
throw new IOException("Header key not found")
if (keyIdx == header.length())
throw new IOException("Header value not found")
String key = header.substring(0, keyIdx)
String value = header.substring(keyIdx + 1)
headers.put(key, value)
}
if (!headers.containsKey("Range"))
throw new IOException("Range header not found")
String range = headers.get("Range").trim()
String[] split = range.split("-")
if (split.length != 2)
throw new IOException("Invalid range header $range")
long start
long end
try {
start = Long.parseLong(split[0])
end = Long.parseLong(split[1])
} catch (NumberFormatException nfe) {
throw new IOException(nfe)
}
if (start < 0 || end < start)
throw new IOException("Invalid range $start - $end")
new Request( infoHash : infoHash, range : new Range(start, end), headers : headers)
}
}

View File

@ -48,8 +48,11 @@ public class UploadManager {
Request request = Request.parse(new InfoHash(infoHashRoot), e.getInputStream())
Uploader uploader = new Uploader(request, e)
eventBus.publish(new UploadEvent(uploader))
uploader.respond()
eventBus.publish(new UploadFinishedEvent(uploader))
try {
uploader.respond()
} finally {
eventBus.publish(new UploadFinishedEvent(uploader))
}
}
}

View File

@ -0,0 +1,108 @@
package com.muwire.core.upload
import java.nio.charset.StandardCharsets
import org.junit.Before
import org.junit.Test
import com.muwire.core.InfoHash
class RequestParsingTest {
Request request
private void fromString(String requestString) {
def is = new ByteArrayInputStream(requestString.getBytes(StandardCharsets.US_ASCII))
request = Request.parse(new InfoHash(new byte[InfoHash.SIZE]), is)
}
private static void failed(String requestString) {
try {
def is = new ByteArrayInputStream(requestString.getBytes(StandardCharsets.US_ASCII))
Request.parse(new InfoHash(new byte[InfoHash.SIZE]), is)
assert false
} catch (IOException expected) {}
}
@Before
public void setup() {
request = null
}
@Test
public void testSuccessful() {
fromString("Range: 1-2\r\n\r\n")
assert request != null
assert request.getRange().start == 1
assert request.getRange().end == 2
}
@Test
public void testRNMissing() {
failed("Range: 1-2")
}
@Test
public void testRNMissing2() {
failed("Range: 1-2\r\n")
}
@Test
public void testRR() {
failed("Range: 1-2\r\r")
}
@Test
public void testNR() {
failed("Range: 1-2\n\r")
}
@Test
public void testR() {
failed("Range: 1-2\r")
}
@Test
public void testRX() {
failed("Range: 1-2\rx")
}
@Test
public void testTwoHeaders() {
fromString("Range: 1-2\r\nA:B\r\n\r\n")
assert request != null
assert request.getRange().start == 1
assert request.getRange().end == 2
assert request.getHeaders().size() == 2
assert request.getHeaders().get("Range").trim() == "1-2"
assert request.getHeaders().get("A").trim() == "B"
}
@Test
public void testRangeMissing() {
failed("A:B\r\n")
}
@Test
public void testNoHeaders() {
failed("\r\n")
}
@Test
public void testInvalidRange() {
failed("Range 1-2\r\n\r\n")
failed("Range:\r\n\r\n")
failed("Range: -1-2\r\n\r\n")
failed("Range: 1-x\r\n\r\n")
failed("Range: x")
}
@Test
public void testHeaderTooLong() {
StringBuilder sb = new StringBuilder()
for (int i = 0; i < (0x1 << 14) + 1; i++)
sb.append("x")
failed(sb.toString())
}
}