Beispiel #1
0
static void writeALot(Stream::ptr stream)
{
    for (size_t i = 0; i < A_LOT_OF_ITERATIONS; ++i) {
        MORDOR_TEST_ASSERT_EQUAL(stream->write("t", 1u), 1u);
        stream->flush(false);
    }
}
Beispiel #2
0
MORDOR_UNITTEST(SSLStream, basic)
{
    WorkerPool pool;
    std::pair<Stream::ptr, Stream::ptr> pipes = pipeStream();

    SSLStream::ptr sslserver(new SSLStream(pipes.first, false));
    SSLStream::ptr sslclient(new SSLStream(pipes.second, true));

    pool.schedule(boost::bind(&accept, sslserver));
    sslclient->connect();
    pool.dispatch();

    Stream::ptr server = sslserver, client = sslclient;

    char buf[6];
    buf[5] = '\0';
    client->write("hello");
    client->flush(false);
    MORDOR_TEST_ASSERT_EQUAL(server->read(buf, 5), 5u);
    MORDOR_TEST_ASSERT_EQUAL((const char *)buf, "hello");
    server->write("world");
    server->flush(false);
    MORDOR_TEST_ASSERT_EQUAL(client->read(buf, 5), 5u);
    MORDOR_TEST_ASSERT_EQUAL((const char *)buf, "world");
}
Beispiel #3
0
MORDOR_UNITTEST(SSLStream, forceDuplex)
{
    WorkerPool pool;
    std::pair<Stream::ptr, Stream::ptr> pipes = pipeStream();

    SSLStream::ptr sslserver(new SSLStream(pipes.first, false));
    SSLStream::ptr sslclient(new SSLStream(pipes.second, true));

    Stream::ptr server = sslserver, client = sslclient;

    int sequence = 0;
    pool.schedule(boost::bind(&accept, sslserver));
    sslclient->connect();
    pool.dispatch();

    pool.schedule(boost::bind(&readWorld, client,
        boost::ref(sequence)));
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    // Read is pending
    client->write("hello");
    client->flush(false);
    pool.dispatch();
    server->write("world");
    server->flush(false);
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
}
Beispiel #4
0
MORDOR_MAIN(int argc, const char * const argv[])
{
    try {
        Config::loadFromEnvironment();
        StdoutStream stdoutStream;
        WorkerPool pool(2);
        if (argc == 1) {
            argc = 2;
            const char * const hyphen[] = { "", "-" };
            argv = hyphen;
        }
        for (int i = 1; i < argc; ++i) {
            Stream::ptr inStream;
            std::string arg(argv[i]);
            if (arg == "-") {
                inStream.reset(new StdinStream());
            } else {
                inStream.reset(new FileStream(arg, FileStream::READ));
            }
            transferStream(inStream, stdoutStream);
        }
    } catch (const std::exception& ex) {
        std::cerr << ex.what() << std::endl;
    }
    return 0;
}
Beispiel #5
0
static void basicInFibers(Stream::ptr stream, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
    MORDOR_TEST_ASSERT_EQUAL(stream->write("a"), 1u);
    stream->close();
    stream->flush();
    ++sequence;
    MORDOR_TEST_ASSERT_EQUAL(sequence, 3);
}
Beispiel #6
0
static void eachConfigVarHTML(ConfigVarBase::ptr var, Stream::ptr stream)
{
    std::string name = var->name();
    stream->write("<tr><td align=\"right\">", 22);
    stream->write(name.c_str(), name.size());
    stream->write("=</td><td>", 10);
    std::string value = var->toString();
    stream->write(value.c_str(), value.size());
    stream->write("</td></tr>\n", 11);
}
Beispiel #7
0
static void cancelOnBlockingWriter(Stream::ptr stream, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    char buffer[4096];
    memset(buffer, 0, sizeof(buffer));
    MORDOR_TEST_ASSERT_EXCEPTION(
        while (true) stream->write(buffer, 4096),
        OperationAbortedException);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
    MORDOR_TEST_ASSERT_EXCEPTION(stream->write(buffer, 4096), OperationAbortedException);
}
Beispiel #8
0
Connection::Connection(Stream::ptr stream)
: m_stream(stream)
{
    MORDOR_ASSERT(stream);
    MORDOR_ASSERT(stream->supportsRead());
    MORDOR_ASSERT(stream->supportsWrite());
    if (!stream->supportsUnread() || !stream->supportsFind()) {
        BufferedStream *buffered = new BufferedStream(stream);
        buffered->allowPartialReads(true);
        m_stream.reset(buffered);
    }
}
Beispiel #9
0
MORDOR_UNITTEST(BufferedStream, partiallyBufferedReadRawBuffer)
{
    MemoryStream::ptr baseStream(new MemoryStream("0123456789"));
    BufferedStream::ptr bufferedStream(new BufferedStream(baseStream));
    bufferedStream->bufferSize(3);
    Stream::ptr stream = bufferedStream;
    char buffer[3];
    buffer[2] = '\0';
    MORDOR_TEST_ASSERT_EQUAL(stream->read(buffer, 2), 2u);
    MORDOR_TEST_ASSERT_EQUAL((const char *)buffer, "01");
    MORDOR_TEST_ASSERT_EQUAL(stream->read(buffer, 2), 2u);
    MORDOR_TEST_ASSERT_EQUAL((const char *)buffer, "23");
}
Beispiel #10
0
static void blockingWrite(Stream::ptr stream, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
    Buffer output;
    MORDOR_TEST_ASSERT_EQUAL(stream->read(output, 10), 5u);
    MORDOR_TEST_ASSERT(output == "hello");
}
Beispiel #11
0
Multipart::Multipart(Stream::ptr stream, std::string boundary)
: m_stream(stream),
  m_boundary(boundary),
  m_finished(false)
{
    MORDOR_ASSERT(m_stream);
    MORDOR_ASSERT(m_stream->supportsRead() || m_stream->supportsWrite());
    MORDOR_ASSERT(!(m_stream->supportsRead() && m_stream->supportsWrite()));
    while (!m_boundary.empty() && m_boundary[m_boundary.size() - 1] == ' ')
        m_boundary.resize(m_boundary.size() - 1);
    MORDOR_ASSERT(!m_boundary.empty());
    MORDOR_ASSERT(m_boundary.size() <= 70);
    if (m_boundary.find_first_not_of(allowedBoundaryChars) != std::string::npos) {
        if (stream->supportsWrite()) {
            MORDOR_ASSERT(false);
        } else {
            MORDOR_THROW_EXCEPTION(InvalidMultipartBoundaryException());
        }
    }
    m_boundary = "\r\n--" + m_boundary;
    if (m_stream->supportsRead()) {
        MORDOR_ASSERT(m_stream->supportsFind());
        MORDOR_ASSERT(m_stream->supportsUnread());
    }
}
Beispiel #12
0
static void writeLotsaData(Stream::ptr stream, unsigned long long toTransfer, bool &complete)
{
    RandomStream random;
    MORDOR_TEST_ASSERT_EQUAL(transferStream(random, stream, toTransfer), toTransfer);
    stream->flush();
    complete = true;
}
Beispiel #13
0
static void eachConfigVarHTMLWrite(ConfigVarBase::ptr var, Stream::ptr stream)
{
    std::string name = var->name();
    stream->write("<tr><td align=\"right\">", 22);
    stream->write(name.c_str(), name.size());
    stream->write("=</td><td><form name=\"", 22);
    stream->write(name.c_str(), name.size());
    stream->write("\" method=\"post\"><input type=\"text\" name=\"", 41);
    stream->write(name.c_str(), name.size());
    stream->write("\" value=\"", 9);
    std::string value = var->toString();
    stream->write(value.c_str(), value.size());
    stream->write("\" /><input type=\"submit\" value=\"Change\" /></form></td></tr>\n", 60);
}
Beispiel #14
0
static void readWorld(Stream::ptr stream, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    char buf[6];
    buf[5] = '\0';
    MORDOR_TEST_ASSERT_EQUAL(stream->read(buf, 5), 5u);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
    MORDOR_TEST_ASSERT_EQUAL((const char *)buf, "world");
}
Beispiel #15
0
void threadStress(Stream::ptr stream)
{
    size_t totalRead = 0;
    size_t totalWritten = 0;
    size_t buf[64];
    Buffer buffer;
    for (int i = 0; i < 10000; ++i) {
        if (i % 2) {
            size_t toRead = 64;
            size_t read = stream->read(buffer, toRead * sizeof(size_t));
            MORDOR_TEST_ASSERT(read % sizeof(size_t) == 0);
            buffer.copyOut(&buf, read);
            for (size_t j = 0; read > 0; read -= sizeof(size_t), ++j) {
                MORDOR_TEST_ASSERT_EQUAL(buf[j], ++totalRead);
            }
            buffer.clear();
        } else {
            size_t toWrite = 64;
            for (size_t j = 0; j < toWrite; ++j) {
                buf[j] = ++totalWritten;
            }
            buffer.copyIn(buf, toWrite * sizeof(size_t));
            size_t written = stream->write(buffer, toWrite * sizeof(size_t));
            totalWritten -= (toWrite - written / sizeof(size_t));
            buffer.clear();
        }
    }
    stream->close(Stream::WRITE);
    while (true) {
        size_t toRead = 64;
        size_t read = stream->read(buffer, toRead);
        if (read == 0)
            break;
        MORDOR_TEST_ASSERT(read % sizeof(size_t) == 0);
        buffer.copyOut(&buf, read);
        for (size_t i = 0; read > 0; read -= sizeof(size_t), ++i) {
            MORDOR_TEST_ASSERT_EQUAL(buf[i], ++totalRead);
        }
        buffer.clear();
    }
    stream->flush();
}
Beispiel #16
0
Stream::ptr
Connection::getStream(const GeneralHeaders &general,
    const EntityHeaders &entity, const std::string &method, Status status,
    boost::function<void()> notifyOnEof,
    boost::function<void()> notifyOnException, bool forRead)
{
    MORDOR_ASSERT(hasMessageBody(general, entity, method, status));
    Stream::ptr stream;
    if (forRead) {
        stream.reset(new SingleplexStream(m_stream, SingleplexStream::READ, false));
    } else {
        stream.reset(new SingleplexStream(m_stream, SingleplexStream::WRITE, false));
    }
    Stream::ptr baseStream(stream);
    for (ParameterizedList::const_reverse_iterator it(general.transferEncoding.rbegin());
        it != general.transferEncoding.rend();
        ++it) {
        if (stricmp(it->value.c_str(), "chunked") == 0) {
            stream.reset(new ChunkedStream(stream));
        } else if (stricmp(it->value.c_str(), "deflate") == 0) {
            stream.reset(new ZlibStream(stream));
        } else if (stricmp(it->value.c_str(), "gzip") == 0 ||
            stricmp(it->value.c_str(), "x-gzip") == 0) {
            stream.reset(new GzipStream(stream));
        } else if (stricmp(it->value.c_str(), "compress") == 0 ||
            stricmp(it->value.c_str(), "x-compress") == 0) {
            MORDOR_ASSERT(false);
        } else if (stricmp(it->value.c_str(), "identity") == 0) {
            MORDOR_ASSERT(false);
        } else {
            MORDOR_ASSERT(false);
        }
    }
    if (stream != baseStream) {
    } else if (entity.contentLength != ~0ull) {
        LimitedStream::ptr limited(new LimitedStream(stream, entity.contentLength));
        limited->strict(true);
        stream = limited;
    } else if (entity.contentType.type == "multipart") {
        // Getting stream to pass to multipart; self-delimiting
    } else {
        // Delimited by closing the connection
    }
    NotifyStream::ptr notify(new NotifyStream(stream));
    stream = notify;
    notify->notifyOnClose = notifyOnEof;
    notify->notifyOnEof = notifyOnEof;
    notify->notifyOnException = notifyOnException;
    return stream;
}
Beispiel #17
0
static void closeOnBlockingWriter(Stream::ptr stream, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
    stream->close();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
}
Beispiel #18
0
Stream::ptr tunnel(HTTP::StreamBroker::ptr streamBroker, const URI &proxy,
    IPAddress::ptr targetIP, const std::string &targetDomain,
    unsigned short targetPort, unsigned char version)
{
    MORDOR_ASSERT(version == 4 || version == 5);
    MORDOR_ASSERT(version == 5 || !targetIP ||
        targetIP->family() == AF_INET);

    MORDOR_ASSERT(streamBroker);
    MORDOR_ASSERT(targetIP || !targetDomain.empty());
    std::string buffer;
    buffer.resize(std::max<size_t>(targetDomain.size() + 1u, 16u) + 9);

    Stream::ptr stream = streamBroker->getStream(proxy);
    if (version == 5) {
        buffer[0] = version;
        buffer[1] = 1;
        buffer[2] = 0;
        size_t written = 0;
        while (written < 3)
            written += stream->write(buffer.data() + written, 3 - written);
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if (buffer[0] != 5)
            MORDOR_THROW_EXCEPTION(ProtocolViolationException());
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if ((unsigned char)buffer[0] == 0xff)
            MORDOR_THROW_EXCEPTION(NoAcceptableAuthenticationMethodException());
        if (buffer[0] != 0)
            MORDOR_THROW_EXCEPTION(ProtocolViolationException());
    }
    buffer[0] = version;
    buffer[1] = 1;
    size_t size;
    if (version == 4) {
        if (targetIP)
            *(unsigned short *)&buffer[2] = htons(targetIP->port());
        else
            *(unsigned short *)&buffer[2] = htons(targetPort);
        if (targetIP)
            *(unsigned int *)&buffer[4] = htonl((unsigned int)(((sockaddr_in *)targetIP->name())->sin_addr.s_addr));
        else
            *(unsigned int *)&buffer[4] = htonl(0x00000001);
        buffer[8] = 0;
        if (!targetIP) {
            memcpy(&buffer[9], targetDomain.c_str(), targetDomain.size());
            buffer[9 + targetDomain.size()] = 0;
        }
        size = 9 + targetDomain.size() + (targetDomain.empty() ? 0 : 1);
    } else {
        buffer[2] = 0;
        if (targetIP) {
            if (targetIP->family() == AF_INET) {
                buffer[3] = 1;
                *(unsigned int *)&buffer[4] = htonl((unsigned int)(((sockaddr_in *)targetIP->name())->sin_addr.s_addr));
                size = 7;
            } else {
                buffer[3] = 4;
                memcpy(&buffer[4], &((sockaddr_in6 *)targetIP->name())->sin6_addr, 16);
                size = 19;
            }
        } else {
            buffer[3] = 3;
            buffer[4] = (unsigned char)targetDomain.size();
            memcpy(&buffer[5], targetDomain.c_str(), targetDomain.size());
            size = 5 + targetDomain.size();
        }
        if (targetIP)
            *(unsigned short *)&buffer[size] = htons(targetIP->port());
        else
            *(unsigned short *)&buffer[size] = htons(targetPort);
        size += 2;
    }
    size_t written = 0;
    while (written < size)
        written += stream->write(buffer.data() + written, size - written);
    if (stream->read(&buffer[0], 1) == 0)
        MORDOR_THROW_EXCEPTION(UnexpectedEofException());
    if ((version == 4 && buffer[0] != 0) || (version == 5 && buffer[0] != 5))
        MORDOR_THROW_EXCEPTION(ProtocolViolationException());
    if (stream->read(&buffer[0], 1) == 0)
        MORDOR_THROW_EXCEPTION(UnexpectedEofException());
    if ((version == 4 && buffer[0] != 0x5a) || (version == 5 && buffer[0] != 0))
        MORDOR_THROW_EXCEPTION(InvalidResponseException(buffer[0]));
    if (version == 4) {
        size = 0;
        while (size < 6) {
            written = stream->read(&buffer[0], 6 - size);
            if (written == 0)
                MORDOR_THROW_EXCEPTION(UnexpectedEofException());
            size += written;
        }
    } else {
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if (buffer[0] != 0)
            MORDOR_THROW_EXCEPTION(InvalidResponseException(buffer[0]));
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if (buffer[1] == 3) {
            if (buffer[0] != 0)
                MORDOR_THROW_EXCEPTION(ProtocolViolationException());
            size = buffer[1] + 2;
        } else if (buffer[1] == 1) {
            size = 6;
        } else if (buffer[1] == 4) {
            size = 18;
        } else {
            MORDOR_THROW_EXCEPTION(ProtocolViolationException());
        }
        while (size > 0) {
            written = stream->read(&buffer[0], size);
            if (written == 0)
                MORDOR_THROW_EXCEPTION(UnexpectedEofException());
            size -= written;
        }
    }
    return stream;
}
Beispiel #19
0
static void readALot(Stream::ptr stream)
{
    unsigned char buffer;
    for (size_t i = 0; i < A_LOT_OF_ITERATIONS; ++i)
        MORDOR_TEST_ASSERT_EQUAL(stream->read(&buffer, 1u), 1u);
}
Beispiel #20
0
static void blockingRead(Stream::ptr stream, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    MORDOR_TEST_ASSERT_EQUAL(stream->write("hello"), 5u);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
}
Beispiel #21
0
void Config::request(ServerRequest::ptr request, Access access)
{
    const std::string &method = request->request().requestLine.method;
    if (method == POST) {
        if (access != READWRITE) {
            respondError(request, FORBIDDEN);
            return;
        }
        if (request->request().entity.contentType.type != "application" ||
            request->request().entity.contentType.subtype != "x-www-form-urlencoded") {
            respondError(request, UNSUPPORTED_MEDIA_TYPE);
            return;
        }
        Stream::ptr requestStream = request->requestStream();
        requestStream.reset(new LimitedStream(requestStream, 65536));
        MemoryStream requestBody;
        transferStream(requestStream, requestBody);
        std::string queryString;
        queryString.resize(requestBody.buffer().readAvailable());
        requestBody.buffer().copyOut(&queryString[0], requestBody.buffer().readAvailable());

        bool failed = false;
        URI::QueryString qs(queryString);
        for (URI::QueryString::const_iterator it = qs.begin();
            it != qs.end();
            ++it) {
            ConfigVarBase::ptr var = Mordor::Config::lookup(it->first);
            if (var && !var->fromString(it->second))
                failed = true;
        }
        if (failed) {
            respondError(request, HTTP::FORBIDDEN,
                "One or more new values were not accepted");
            return;
        }
        // Fall through
    }
    if (method == GET || method == HEAD || method == POST) {
        Format format = HTML;
        URI::QueryString qs;
        if (request->request().requestLine.uri.queryDefined())
            qs = request->request().requestLine.uri.queryString();
        URI::QueryString::const_iterator it = qs.find("alt");
        if (it != qs.end() && it->second == "json")
            format = JSON;
        // TODO: use Accept to indicate JSON
        switch (format) {
            case HTML:
            {
                request->response().status.status = OK;
                request->response().entity.contentType = MediaType("text", "html");
                if (method == HEAD) {
                    if (request->request().requestLine.ver == Version(1, 1) &&
                        isAcceptable(request->request().request.te, "chunked", true)) {
                        request->response().general.transferEncoding.push_back("chunked");
                    }
                    return;
                }
                Stream::ptr response = request->responseStream();
                response.reset(new BufferedStream(response));
                response->write("<html><body><table>\n", 20);
                Mordor::Config::visit(boost::bind(access == READWRITE ?
                    &eachConfigVarHTMLWrite : &eachConfigVarHTML, _1,
                    response));
                response->write("</table></body></html>", 22);
                response->close();
                break;
            }
            case JSON:
            {
                JSON::Object root;
                Mordor::Config::visit(boost::bind(&eachConfigVarJSON, _1, boost::ref(root)));
                std::ostringstream os;
                os << root;
                std::string str = os.str();
                request->response().status.status = OK;
                request->response().entity.contentType = MediaType("application", "json");
                request->response().entity.contentLength = str.size();
                if (method != HEAD) {
                    request->responseStream()->write(str.c_str(), str.size());
                    request->responseStream()->close();
                }
                break;
            }
            default:
                MORDOR_NOTREACHED();
        }
    } else {
        respondError(request, METHOD_NOT_ALLOWED);
    }
}
Beispiel #22
0
static void cancelOnBlockingReader(Stream::ptr stream, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    stream->cancelRead();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
}
Beispiel #23
0
static void copyIn(IOManager *ioManager = NULL)
{
    Connection conn(g_goodConnString, ioManager);
    conn.execute("CREATE TEMP TABLE stuff (id INTEGER, name TEXT)");
    Stream::ptr stream = conn.copyIn("stuff").csv()();
    stream->write("1,cody\n");
    stream->write("2,tom\n");
    stream->write("3,brian\n");
    stream->write("4,jeremy\n");
    stream->write("5,zach\n");
    stream->write("6,paul\n");
    stream->write("7,alen\n");
    stream->write("8,jt\n");
    stream->write("9,jon\n");
    stream->write("10,jacob\n");
    stream->close();
    Result result = conn.execute("SELECT COUNT(*) FROM stuff");
    MORDOR_TEST_ASSERT_EQUAL(result.rows(), 1u);
    MORDOR_TEST_ASSERT_EQUAL(result.columns(), 1u);
    MORDOR_TEST_ASSERT_EQUAL(result.get<long long>(0, 0), 10);
    result = conn.execute("SELECT SUM(id) FROM stuff");
    MORDOR_TEST_ASSERT_EQUAL(result.rows(), 1u);
    MORDOR_TEST_ASSERT_EQUAL(result.columns(), 1u);
    MORDOR_TEST_ASSERT_EQUAL(result.get<long long>(0, 0), 55);
}