bool JsonSerializer::input(Pair &pair) { String key; if(!input(key)) return false; AssertIO(mStream->last() == ':'); LineSerializer keySerializer(&key); pair.deserializeKey(keySerializer); AssertIO(pair.deserializeValue(*this)); return true; }
void Resource::fetch(const BinaryString &digest, bool localOnly) { delete mIndexBlock; delete mIndexRecord; mIndexRecord = NULL; mIndexBlock = NULL; if(localOnly && !Store::Instance->hasBlock(digest)) throw Exception(String("Local resource not found: ") + digest.toString()); //LogDebug("Resource::fetch", "Fetching resource " + digest.toString()); try { mIndexBlock = new Block(digest); mIndexRecord = new IndexRecord; //LogDebug("Resource::fetch", "Reading index block for " + digest.toString()); BinarySerializer serializer(mIndexBlock); AssertIO(static_cast<Serializer*>(&serializer)->input(mIndexRecord)); } catch(const std::exception &e) { delete mIndexBlock; delete mIndexRecord; mIndexRecord = NULL; mIndexBlock = NULL; throw Exception(String("Unable to fetch resource index block: ") + e.what()); } }
void Http::Request::recv(Stream *stream, bool parsePost) { Assert(stream); this->stream = stream; clear(); // Read first line String line; if(!stream->readLine(line)) throw NetException("Connection closed"); method.clear(); url.clear(); line.readString(method); line.readString(url); String protocol; line.readString(protocol); version = protocol.cut('/'); if(url.empty() || version.empty() || protocol != "HTTP") throw 400; if(method != "GET" && method != "POST" && method != "HEAD") throw 405; // Read headers while(true) { String line; AssertIO(stream->readLine(line)); if(line.empty()) break; String value = line.cut(':'); line.trim(); value.trim(); headers.insert(line,value); } // Read cookies String cookie; if(headers.get("Cookie", cookie)) { while(!cookie.empty()) { String next = cookie.cut(';'); String value = cookie.cut('='); cookie.trim(); value.trim(); cookies.insert(cookie,value); cookie = next; } } fullUrl = url; // Read URL variables String getData = url.cut('?'); if(!getData.empty()) { List<String> exploded; getData.explode(exploded,'&'); for( List<String>::iterator it = exploded.begin(); it != exploded.end(); ++it) { String value = it->cut('=').urlDecode(); get.insert(it->urlDecode(), value); } } url = url.urlDecode(); String expect; if((headers.get("Expect",expect) && expect.toLower() == "100-continue") || (method == "POST" && version == "1.1")) { stream->write("HTTP/1.1 100 Continue\r\n\r\n"); } // Read post variables if(method == "POST" && parsePost) { if(!headers.contains("Content-Length")) throw Exception("Missing Content-Length header in POST request"); size_t contentLength = 0; headers["Content-Length"].extract(contentLength); String contentType; if(headers.get("Content-Type", contentType)) { String parameters = contentType.cut(';'); contentType.trim(); if(contentType == "application/x-www-form-urlencoded") { String data; if(stream->read(data, contentLength) != contentLength) throw NetException("Connection unexpectedly closed"); List<String> exploded; data.explode(exploded,'&'); for( List<String>::iterator it = exploded.begin(); it != exploded.end(); ++it) { String value = it->cut('=').urlDecode(); post.insert(it->urlDecode(), value); } } else if(contentType == "multipart/form-data") { String boundary; while(true) { String key; if(!parameters.readUntil(key,';')) break; String value = key.cut('='); key.trim(); value.trim(); value.trimQuotes(); if(key == "boundary") boundary = String("--") + value; } Assert(!boundary.empty()); String line; while(line.empty()) AssertIO(stream->readLine(line)); Assert(line == boundary); bool finished = false; while(!finished) { StringMap mimeHeaders; while(true) { String line; AssertIO(stream->readLine(line)); if(line.empty()) break; String value = line.cut(':'); line.trim(); value.trim(); mimeHeaders.insert(line,value); } String contentType; if(mimeHeaders.get("Content-Type", contentType)) { String parameters = contentType.cut(';'); contentType.trim(); } String contentDisposition; if(!mimeHeaders.get("Content-Disposition", contentDisposition)) throw Exception("Missing Content-Disposition header in multipart POST request"); String parameters = contentDisposition.cut(';'); contentDisposition.trim(); String name, fileName; while(true) { String key; if(!parameters.readUntil(key,';')) break; String value = key.cut('='); key.trim(); value.trim(); value.trimQuotes(); if(key == "name") name = value; else if(key == "filename") fileName = value; } Stream *output = NULL; if(fileName.empty()) output = &post[name]; else { post[name] = fileName; TempFile *tempFile = new TempFile(); files[name] = tempFile; output = tempFile; LogDebug("Http::Request", String("File upload: ") + fileName); } String contentLength; if(mimeHeaders.get("Content-Length", contentLength)) { int64_t size = 0; contentLength >> size; stream->read(*output,size); String line; AssertIO(stream->readLine(line)); AssertIO(stream->readLine(line)); if(line == boundary + "--") finished = true; else AssertIO(line == boundary); } else { /*String line; while(stream->readLine(line)) { if(line == boundary) break; output->write(line); line.clear(); }*/ // TODO: This must be replaced with Boyer-Moore algorithm for performance String bound = String("\r\n") + boundary; char *buffer = new char[bound.size()]; try { int size = 0; int c = 0; int i = 0; while(true) { if(c == size) { c = 0; size = stream->readData(buffer,bound.size()-i); AssertIO(size); } if(buffer[c] == bound[i]) { ++i; ++c; if(i == bound.size()) { // If we are here there is no data left in buffer String line; AssertIO(stream->readLine(line)); if(line == "--") finished = true; break; } } else { if(i) output->writeData(bound.data(), i); int d = c; while(c != size && buffer[c] != bound[0]) ++c; if(c != d) output->writeData(buffer + d, c - d); i = 0; } } } catch(...) { delete[] buffer; throw; } delete[] buffer; } }
bool JsonSerializer::input(String &str) { const String fieldDelimiters = ",:]}"; str.clear(); char chr; if(!mStream->get(chr)) return false; while(Stream::BlankCharacters.contains(chr)) if(!mStream->get(chr)) return false; if(fieldDelimiters.contains(chr)) { if(chr == '}' || chr == ']') { do { if(!mStream->get(chr)) return false; } while(Stream::BlankCharacters.contains(chr)); } return false; } // Special case: read map or array in string if(chr == '{' || chr == '[') { char opening = chr; char closing; if(opening == '{') closing = '}'; else closing = ']'; int count = 1; str+= chr; while(count) { AssertIO(mStream->get(chr)); str+= chr; if(chr == opening) ++count; else if(chr == closing) --count; } do { if(!mStream->get(chr)) return true; } while(Stream::BlankCharacters.contains(chr)); AssertIO(fieldDelimiters.contains(chr)); return true; } bool quotes = (chr == '\'' || chr == '\"'); String delimiters; if(quotes) { delimiters = String(chr); AssertIO(mStream->get(chr)); } else { str+= chr; delimiters = Stream::BlankCharacters; delimiters+=fieldDelimiters; if(!mStream->get(chr)) return true; } while(!delimiters.contains(chr)) { if(chr == '\\') { AssertIO(mStream->get(chr)); switch(chr) { case 'b': chr = '\b'; break; case 'f': chr = '\f'; break; case 'n': chr = '\n'; break; case 'r': chr = '\r'; break; case 't': chr = '\t'; break; case 'u': { String tmp; AssertIO(mStream->read(tmp, 4)); unsigned u = 0; tmp.hexaMode(true); tmp >> u; wchar_t wstr[2]; wstr[0] = wchar_t(u); wstr[1] = 0; str+= String(wstr); chr = 0; break; } default: if(isalpha(chr) || isdigit(chr)) chr = 0; // unknown escape sequence break; } } if(chr) str+= chr; if(!mStream->get(chr)) { if(quotes) throw IOException(); else break; } }