use of io.questdb.std.str.DirectByteCharSequence in project questdb by bluestreak01.
the class HttpMultipartContentParserTest method testSimple.
@Test
public void testSimple() throws Exception {
TestUtils.assertMemoryLeak(() -> {
try (HttpMultipartContentParser multipartContentParser = new HttpMultipartContentParser(new HttpHeaderParser(1024, pool))) {
final String content = "------WebKitFormBoundaryxFKYDBybTLu2rb8P\r\n" + "Content-Disposition: form-data; name=\"textline\"\r\n" + "\r\n" + "value1" + "\r\n" + "------WebKitFormBoundaryxF" + "\r\n" + "------WebKitFormBoundaryxFKYDBybTLu2rb8P\r\n" + "Content-Disposition: form-data; name=\"textline2\"\n" + "\r\n" + "value2\r\n" + "------WebKitFormBoundaryxFKYDBybTLu2rb8PZ" + "\r\n" + "------WebKitFormBoundaryxFKYDBybTLu2rb8P\r\n" + "Content-Disposition: form-data; name=\"datafile\"; filename=\"pom.xml\"\r\n" + "Content-Type: text/xml\r\n" + "\r\n" + "this is a file" + "\r\n" + "------WebKitFormBoundaryxFKYDBybTLu2rb8P--\r\n";
String expected = "Content-Disposition: form-data; name=\"textline\"\r\n" + "\r\n" + "value1" + "\r\n" + "------WebKitFormBoundaryxF" + "\r\n" + "-----------------------------\r\n" + "Content-Disposition: form-data; name=\"textline2\"\r\n" + "\r\n" + "value2\r\n" + "------WebKitFormBoundaryxFKYDBybTLu2rb8PZ\r\n" + "-----------------------------\r\n" + "Content-Disposition: form-data; name=\"datafile\"; filename=\"pom.xml\"\r\n" + "Content-Type: text/xml\r\n" + "\r\n" + "this is a file\r\n" + "-----------------------------\r\n";
int len = content.length();
long p = TestUtils.toMemory(content);
try {
String boundary = "\r\n------WebKitFormBoundaryxFKYDBybTLu2rb8P";
long pBoundary = TestUtils.toMemory(boundary);
DirectByteCharSequence boundaryCs = new DirectByteCharSequence().of(pBoundary, pBoundary + boundary.length());
try {
for (int i = 0; i < len; i++) {
sink.clear();
multipartContentParser.clear();
multipartContentParser.of(boundaryCs);
multipartContentParser.parse(p, p + i, LISTENER);
multipartContentParser.parse(p + i, p + i + 1, LISTENER);
if (len > i + 1) {
multipartContentParser.parse(p + i + 1, p + len, LISTENER);
}
TestUtils.assertEquals(expected, sink);
}
} finally {
Unsafe.free(pBoundary, boundary.length(), MemoryTag.NATIVE_DEFAULT);
}
} finally {
Unsafe.free(p, len, MemoryTag.NATIVE_DEFAULT);
}
}
});
}
use of io.questdb.std.str.DirectByteCharSequence in project questdb by bluestreak01.
the class HttpMultipartContentParserTest method testBreaksCsvImportAt.
private void testBreaksCsvImportAt(int breakAt, RuntimeException onChunkException) throws Exception {
TestHttpMultipartContentListener listener = new TestHttpMultipartContentListener(onChunkException);
TestUtils.assertMemoryLeak(() -> {
try (HttpMultipartContentParser multipartContentParser = new HttpMultipartContentParser(new HttpHeaderParser(1024, pool))) {
String boundaryToken = "------------------------27d997ca93d2689d";
String boundary = "\r\n--" + boundaryToken;
final String content = "--" + boundaryToken + "\r\n" + "Content-Disposition: form-data; name=\"data\"; filename=\"02.csv\"\r\n" + "\r\n" + "B00014,,,\r\n" + "--" + boundaryToken + "--";
final String expected = "Content-Disposition: form-data; name=\"data\"; filename=\"02.csv\"\r\n" + "\r\n" + "B00014,,,\r\n" + "-----------------------------\r\n";
if (breakAt >= content.length())
return;
int len = content.length();
long p = TestUtils.toMemory(content);
try {
long pBoundary = TestUtils.toMemory(boundary);
DirectByteCharSequence boundaryCs = new DirectByteCharSequence().of(pBoundary, pBoundary + boundary.length());
try {
multipartContentParser.clear();
multipartContentParser.of(boundaryCs);
long breakPoint = p + len - breakAt;
long hi = p + len;
boolean result = parseWithRetry(listener, multipartContentParser, p, breakPoint);
if (hi > breakPoint) {
result = parseWithRetry(listener, multipartContentParser, breakPoint, hi);
}
Assert.assertEquals("Break at " + breakAt, expected, sink.toString());
Assert.assertTrue("Break at " + breakAt, result);
} finally {
Unsafe.free(pBoundary, boundary.length(), MemoryTag.NATIVE_DEFAULT);
}
} finally {
Unsafe.free(p, len, MemoryTag.NATIVE_DEFAULT);
}
}
});
}
use of io.questdb.std.str.DirectByteCharSequence in project questdb by bluestreak01.
the class JsonQueryProcessor method parseUrl.
private boolean parseUrl(JsonQueryProcessorState state, CharSequence keepAliveHeader) throws PeerDisconnectedException, PeerIsSlowToReadException {
// Query text.
final HttpRequestHeader header = state.getHttpConnectionContext().getRequestHeader();
final DirectByteCharSequence query = header.getUrlParam("query");
if (query == null || query.length() == 0) {
state.info().$("Empty query header received. Sending empty reply.").$();
sendException(state.getHttpConnectionContext().getChunkedResponseSocket(), 0, "No query text", query, keepAliveHeader);
return false;
}
// Url Params.
long skip = 0;
long stop = Long.MAX_VALUE;
CharSequence limit = header.getUrlParam("limit");
if (limit != null) {
int sepPos = Chars.indexOf(limit, ',');
try {
if (sepPos > 0) {
skip = Numbers.parseLong(limit, 0, sepPos) - 1;
if (sepPos + 1 < limit.length()) {
stop = Numbers.parseLong(limit, sepPos + 1, limit.length());
}
} else {
stop = Numbers.parseLong(limit);
}
} catch (NumericException ex) {
// Skip or stop will have default value.
}
}
if (stop < 0) {
stop = 0;
}
if (skip < 0) {
skip = 0;
}
if ((stop - skip) > configuration.getMaxQueryResponseRowLimit()) {
stop = skip + configuration.getMaxQueryResponseRowLimit();
}
try {
state.configure(header, query, skip, stop);
} catch (Utf8Exception e) {
state.info().$("Bad UTF8 encoding").$();
sendException(state.getHttpConnectionContext().getChunkedResponseSocket(), 0, "Bad UTF8 encoding in query text", query, keepAliveHeader);
return false;
}
return true;
}
use of io.questdb.std.str.DirectByteCharSequence in project questdb by bluestreak01.
the class JsonQueryProcessorState method of.
boolean of(RecordCursorFactory factory, SqlExecutionContextImpl sqlExecutionContext) throws PeerDisconnectedException, PeerIsSlowToReadException, SqlException {
this.recordCursorFactory = factory;
queryCacheable = true;
this.cursor = factory.getCursor(sqlExecutionContext);
final RecordMetadata metadata = factory.getMetadata();
HttpRequestHeader header = httpConnectionContext.getRequestHeader();
DirectByteCharSequence columnNames = header.getUrlParam("cols");
int columnCount;
columnSkewList.clear();
if (columnNames != null) {
columnsQueryParameter.clear();
try {
TextUtil.utf8Decode(columnNames.getLo(), columnNames.getHi(), columnsQueryParameter);
} catch (Utf8Exception e) {
info().$("utf8 error when decoding column list '").$(columnNames).$('\'').$();
HttpChunkedResponseSocket socket = getHttpConnectionContext().getChunkedResponseSocket();
JsonQueryProcessor.header(socket, "");
socket.put('{').putQuoted("error").put(':').putQuoted("utf8 error in column list");
socket.put('}');
socket.sendChunk(true);
return false;
}
columnCount = 1;
int start = 0;
int comma = 0;
while (comma > -1) {
comma = Chars.indexOf(columnsQueryParameter, start, ',');
if (comma > -1) {
if (addColumnToOutput(metadata, columnsQueryParameter, start, comma)) {
return false;
}
start = comma + 1;
columnCount++;
} else {
int hi = columnsQueryParameter.length();
if (addColumnToOutput(metadata, columnsQueryParameter, start, hi)) {
return false;
}
}
}
} else {
columnCount = metadata.getColumnCount();
for (int i = 0; i < columnCount; i++) {
addColumnTypeAndName(metadata, i);
}
}
this.columnCount = columnCount;
return true;
}
use of io.questdb.std.str.DirectByteCharSequence in project questdb by bluestreak01.
the class HttpHeaderParser method urlDecode.
private int urlDecode(long lo, long hi, CharSequenceObjHashMap<DirectByteCharSequence> map) {
long _lo = lo;
long rp = lo;
long wp = lo;
int offset = 0;
CharSequence name = null;
while (rp < hi) {
char b = (char) Unsafe.getUnsafe().getByte(rp++);
switch(b) {
case '=':
if (_lo < wp) {
name = pool.next().of(_lo, wp);
}
_lo = rp - offset;
break;
case '&':
if (name != null) {
map.put(name, pool.next().of(_lo, wp));
name = null;
}
_lo = rp - offset;
break;
case '+':
Unsafe.getUnsafe().putByte(wp++, (byte) ' ');
continue;
case '%':
try {
if (rp + 1 < hi) {
byte bb = (byte) Numbers.parseHexInt(temp.of(rp, rp += 2));
Unsafe.getUnsafe().putByte(wp++, bb);
offset += 2;
continue;
}
} catch (NumericException ignore) {
}
throw HttpException.instance("invalid query encoding");
default:
break;
}
Unsafe.getUnsafe().putByte(wp++, (byte) b);
}
if (_lo < wp && name != null) {
map.put(name, pool.next().of(_lo, wp));
}
return offset;
}
Aggregations