示例#1
0
// Test that only cookies we manually add to the header are sent.
void HttpClientTest::testCookies()
{
    bp::url::Url url(m_testServer.getEchoUrl());
    RequestPtr ptrReq(new Request(Method::HTTP_POST, url));

    // Tell the test server to echo request headers in response body.
    QueryString qs;
    qs.add("EchoHeaders", bp::conv::toString(1));
    ptrReq->url.setQuery(qs.toString());

    // Add some cookie headers.
    string sCookie = "kind=oatmeal";
    Headers hdrs;
    hdrs.add( Headers::ksCookie, "kind=oatmeal" );
    ptrReq->headers = hdrs;
    
    // Dummy body.
    const string ksBody = "Cookies are delicious";
    ptrReq->body.assign(ksBody);

    // Execute the transaction.
    SyncTransactionPtr tran = SyncTransaction::alloc(ptrReq);
    SyncTransaction::FinalStatus results;
    ResponsePtr ptrResp = tran->execute(results);
    CPPUNIT_ASSERT(results.code == SyncTransaction::FinalStatus::eOk);
    CPPUNIT_ASSERT(ptrResp->status.code() == Status::OK);

    string sBody = ptrResp->body.toString();
    string sCookieHdr = "Cookie: " + sCookie;
    string::size_type nIdx = sBody.find( sCookieHdr );
    CPPUNIT_ASSERT( nIdx != string::npos);
}
示例#2
0
Request* Request::clone(ExceptionState& exceptionState) const
{
    if (bodyUsed()) {
        exceptionState.throwTypeError("Request body is already used");
        return nullptr;
    }

    FetchRequestData* request = m_request->clone();
    if (blobDataHandle() && isBodyConsumed()) {
        // Currently the only methods that can consume body data without
        // setting 'body passed' flag consume entire body (e.g. text()). Thus
        // we can set an empty blob to the new request instead of creating a
        // draining stream.
        // TODO(yhirano): Fix this once Request.body is introduced.
        OwnPtr<BlobData> blobData = BlobData::create();
        blobData->setContentType(blobDataHandle()->type());
        request->setBlobDataHandle(BlobDataHandle::create(blobData.release(), 0));
    }

    Headers* headers = Headers::create(request->headerList());
    headers->setGuard(m_headers->guard());
    Request* r = new Request(executionContext(), request, headers);
    r->suspendIfNeeded();
    return r;
}
示例#3
0
bool HttpServerResponse::writeHead(int statusCode,
                                   const QByteArray &reasonPhrase,
                                   const Headers &headers)
{
    if (priv->formattingState != Priv::STATUS_LINE)
        return false;

    if (priv->options.testFlag(HttpServerResponse::HTTP_1_0)) {
        static const char chunk[] = "HTTP/1.0 ";
        priv->device.write(chunk, sizeof(chunk) - 1);
    } else {
        static const char chunk[] = "HTTP/1.1 ";
        priv->device.write(chunk, sizeof(chunk) - 1);
    }

    priv->device.write(QByteArray::number(statusCode));
    priv->device.write(" ", 1);
    priv->device.write(reasonPhrase);
    priv->device.write(CRLF);

    for (Headers::const_iterator i = headers.constBegin()
         ;i != headers.end();++i) {
        priv->device.write(i.key());
        priv->device.write(": ", 2);
        priv->device.write(i.value());
        priv->device.write(CRLF);
    }
    priv->formattingState = Priv::HEADERS;
    return true;
}
示例#4
0
void HTTPConnection::respondWithStatusAndHeaders(const char* code, const char* contentType, const Headers& headers, qint64 contentLength) {
    _socket->write("HTTP/1.1 ");

    _socket->write(code);
    _socket->write("\r\n");

    for (Headers::const_iterator it = headers.constBegin(), end = headers.constEnd();
            it != end; it++) {
        _socket->write(it.key());
        _socket->write(": ");
        _socket->write(it.value());
        _socket->write("\r\n");
    }

    if (contentLength > 0) {
        _socket->write("Content-Length: ");
        _socket->write(QByteArray::number(contentLength));
        _socket->write("\r\n");

        _socket->write("Content-Type: ");
        _socket->write(contentType);
        _socket->write("\r\n");
    }
    _socket->write("Connection: close\r\n\r\n");
}
示例#5
0
Headers::const_iterator findHeader(const Headers& headers, 
                                   const std::string& name)
{
   return std::find_if(headers.begin(), 
                       headers.end(), 
                       HeaderNamePredicate(name));
}
示例#6
0
void HTTPConnection::respond(const char* code, const QByteArray& content, const char* contentType, const Headers& headers) {
    _socket->write("HTTP/1.1 ");
    _socket->write(code);
    _socket->write("\r\n");

    int csize = content.size();

    for (Headers::const_iterator it = headers.constBegin(), end = headers.constEnd();
            it != end; it++) {
        _socket->write(it.key());
        _socket->write(": ");
        _socket->write(it.value());
        _socket->write("\r\n");
    }
    if (csize > 0) {
        _socket->write("Content-Length: ");
        _socket->write(QByteArray::number(csize));
        _socket->write("\r\n");

        _socket->write("Content-Type: ");
        _socket->write(contentType);
        _socket->write("\r\n");
    }
    _socket->write("Connection: close\r\n\r\n");

    if (csize > 0) {
        _socket->write(content);
    }

    // make sure we receive no further read notifications
    _socket->disconnect(SIGNAL(readyRead()), this);

    _socket->disconnectFromHost();
}
示例#7
0
bool HttpServerResponse::addTrailers(const Headers &headers)
{
    if (priv->options.testFlag(HttpServerResponse::HTTP_1_0))
        return false;

    switch (priv->formattingState) {
    case Priv::STATUS_LINE:
    case Priv::END:
    case Priv::HEADERS:
        return false;
    case Priv::MESSAGE_BODY:
        priv->device.write("0\r\n");
        priv->formattingState = Priv::TRAILERS;
    case Priv::TRAILERS:
    {
        for (Headers::const_iterator i = headers.constBegin()
             ;i != headers.end();++i) {
            priv->device.write(i.key());
            priv->device.write(": ", 2);
            priv->device.write(i.value());
            priv->device.write(CRLF);
        }
    }
    } // switch (priv->formattingState)
    return true;
}
示例#8
0
void QPalringoConnection::onPingReceived( const Headers, const QByteArray /* body */ )
{
    Headers h;
    if( protocolVersion_ == 2 )
    {
        h.insert( qpHeaderAttribute::PS, packetSeq_ );
    }

    sendCmd( qpCommand::PING, h, "");
}
示例#9
0
std::string headerValue(const Headers& headers, const std::string& name)
{
   Headers::const_iterator it = std::find_if(headers.begin(), 
                                             headers.end(), 
                                             HeaderNamePredicate(name))  ;
   
   if ( it != headers.end() )
      return (*it).value ;
   else
      return std::string() ;
}
示例#10
0
Response* Response::clone(ExceptionState& exceptionState)
{
    if (isBodyLocked() || bodyUsed()) {
        exceptionState.throwTypeError("Response body is already used");
        return nullptr;
    }

    FetchResponseData* response = m_response->clone(executionContext());
    Headers* headers = Headers::create(response->headerList());
    headers->setGuard(m_headers->guard());
    return new Response(executionContext(), response, headers);
}
示例#11
0
    void assign(const Message& message, const Headers& extraHeaders)
    {
        body_ = message.body_;
        httpVersionMajor_ = message.httpVersionMajor_;
        httpVersionMinor_ = message.httpVersionMinor_;
        headers_ = message.headers_;
        overrideHeader_ = message.overrideHeader_;
        httpVersion_ = message.httpVersion_;

        std::for_each(extraHeaders.begin(), extraHeaders.end(),
                      boost::bind(&Message::setExtraHeader, this, _1));
    }
示例#12
0
void P2pRpcConnection::onNotifyEvent(cstring event, const ObjectList& args)
{
	if(eventMap.contain(event)){
		//remote method name
		String method = eventMap.getDefault(event, "");
		//this->cast(method, args);
		Headers headers;
		headers.put(KEY_RESPONSE, "true");
		headers.put(KEY_CONTENT_TYPE, this->serializerType);
		;
		sendEvent(headers, method, args);
	}
}
示例#13
0
/**
* @brief 
*
* @param headers
* @param payload
* @param statusCode
* @param statusText
*
* @return 
*/
bool RtspConnection::sendResponse( Headers &headers, std::string payload, int statusCode, std::string statusText )
{
    std::string response;

    response = stringtf( "RTSP/1.0 %d %s\r\n", statusCode, statusText.c_str() );

    //headers.insert( Headers::value_type( "Server", "ZoneMinder Streamer V2.0" ) );
    headers.insert( Headers::value_type( "Date", datetimeInet() ) );
    for ( Headers::iterator iter = headers.begin(); iter != headers.end(); iter++ )
    {
        response += iter->first+": "+iter->second+"\r\n";
    }
    response += "\r\n";

    if ( payload.size() )
    {
        response += payload;
    }

    Debug( 2, "Sending RTSP response: %s", response.c_str() );

    if ( mSocket->send( response.c_str(), response.size() ) != (int)response.length() )
    {
        Error( "Unable to send response '%s': %s", response.c_str(), strerror(errno) );
        return( false );
    }

#if 0
    // Not currently used. If RTSP over HTTP ever required then will need to do something like this
    if ( mMethod == RTP_OZ_RTSP_HTTP )
    {
        response = base64Encode( response );
        Debug( 2, "Sending encoded RTSP response: %s", response.c_str() );
        if ( mRtspSocket2.send( response.c_str(), response.size() ) != (int)response.length() )
        {
            Error( "Unable to send response '%s': %s", response.c_str(), strerror(errno) );
            return( false );
        }
    }
    else
    {
        if ( mRtspSocket.send( response.c_str(), response.size() ) != (int)response.length() )
        {
            Error( "Unable to send response '%s': %s", response.c_str(), strerror(errno) );
            return( false );
        }
    }
#endif
    return( true );
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
size_t ChValidation::ReadDataFile(const std::string& filename,
                                  char               delim,
                                  Headers&           headers,
                                  Data&              data)
{
  std::ifstream ifile(filename.c_str());
  std::string   line;

  // Count the number of lines in the file then rewind the input file stream.
  size_t num_lines = std::count(std::istreambuf_iterator<char>(ifile),
                                std::istreambuf_iterator<char>(), '\n');
  ifile.seekg(0, ifile.beg);

  size_t num_data_points = num_lines - 3;

  // Skip the first two lines.
  std::getline(ifile, line);
  std::getline(ifile, line);

  // Read the line with column headers.
  std::getline(ifile, line);
  std::stringstream iss1(line);
  std::string col_header = "";

  while (std::getline(iss1, col_header, delim))
    headers.push_back(col_header);

  size_t num_cols = headers.size();

  // Resize data
  data.resize(num_cols);
  for (size_t col = 0; col < num_cols; col++)
    data[col].resize(num_data_points);

  // Read the actual data, one line at a time.
  size_t row = 0;
  while (std::getline(ifile, line)) {
    std::stringstream iss(line);
    for (size_t col = 0; col < num_cols; col++)
      iss >> data[col][row];
    row++;
  }

  return row;
}
示例#15
0
bool CWsgiEngine::finalizeHeadersWrite(Context *c, quint16 status, const Headers &headers, void *engineData)
{
    auto conn = static_cast<QIODevice*>(engineData);

    conn->write("HTTP/1.1 ", 9);
    int msgLen;
    const char *msg = httpStatusMessage(status, &msgLen);
    conn->write(msg, msgLen);

    auto sock = qobject_cast<TcpSocket*>(conn);
    const auto headersData = headers.data();
    if (sock->headerClose == 1) {
        sock->headerClose = 0;
    }

    bool hasDate = false;
    auto it = headersData.constBegin();
    const auto endIt = headersData.constEnd();
    while (it != endIt) {
        const QString key = it.key();
        const QString value = it.value();
        if (sock->headerClose == 0 && key == QLatin1String("connection")) {
            if (value.compare(QLatin1String("close"), Qt::CaseInsensitive) == 0) {
                sock->headerClose = 2;
            } else {
                sock->headerClose = 1;
            }
        } else if (!hasDate && key == QLatin1String("date")) {
            hasDate = true;
        }

        QString ret(QLatin1String("\r\n") + camelCaseHeader(key) + QLatin1String(": ") + value);
        conn->write(ret.toLatin1());

        ++it;
    }

    if (!hasDate) {
        static QByteArray lastDate = dateHeader();
        static QElapsedTimer timer = timerSetup();
        if (timer.hasExpired(1000)) {
            lastDate = dateHeader();
            timer.restart();
        }
        conn->write(lastDate);
    }

    static QByteArray server = serverHeader();
    conn->write(server);

    return conn->write("\r\n\r\n", 4) == 4;
}
示例#16
0
JSON::Dict &Request::parseJSONArgs() {
  Headers hdrs = getInputHeaders();

  if (hdrs.hasContentType() &&
      String::startsWith(hdrs.getContentType(), "application/json")) {

    Buffer buf = getInputBuffer();
    if (buf.getLength()) {
      Event::BufferStream<> stream(buf);
      JSON::Reader reader(stream);

      // Find start of dict & parse keys into request args
      if (reader.next() == '{') {
        JSON::ValuePtr argsPtr = JSON::ValuePtr::Phony(&args);
        JSON::Builder builder(argsPtr);
        reader.parseDict(builder);
      }
    }
  }

  return args;
}
示例#17
0
void makeNodesHeader(const boost::filesystem::path& output, const Builder& builder, const Headers& headerFileNames)
{
	boost::filesystem::path hpath = output, spath = output;
	hpath /= "nodes.hpp";
	spath /= "nodes.cpp";
	boost::filesystem::ofstream h(hpath.c_str());
	boost::filesystem::ofstream s(spath.c_str());

	h << "/* Automatically generated by ast-gen. DO NOT MODIFY. */\n";
	h << "#pragma once\n";
	for (Headers::const_iterator it = headerFileNames.begin(); it != headerFileNames.end(); it++) {
		h << "#include \"maxwell/ast/nodes/" << *it << "\"\n";
	}
	h << "#include <string>\n";

	s << "/* Automatically generated by ast-gen. DO NOT MODIFY. */\n";
	s << "#include \"maxwell/ast/nodes/nodes.hpp\"\n\n";

	// Generate the node factory class.
	h << "\nnamespace ast {\n\n";
	// h << "class NodeFactory\n{\npublic:\n";
	// h << "\tstatic NodePtr make(const std::string& name);\n";
	// h << "};\n";
	h << "NodePtr makeNode(const std::string& name);\n\n";
	h << "} // namespace ast\n\n";

	// s << "NodePtr NodeFactory::make(const std::string& name) {\n";
	s << "ast::NodePtr ast::makeNode(const std::string& name) {\n";
	s << "\tsize_t size = name.size();\n";
	NodeNames names;
	for (Builder::Nodes::const_iterator it = builder.nodes.begin(); it != builder.nodes.end(); it++) {
		names.insert(it->first);
	}
	generateFactoryBody(s, names, 1);
	s << "\tthrow std::runtime_error(\"Node class name '\" + name + \"' not known to NodeFactory.\");\n";
	s << "}\n";
}
示例#18
0
bool uWSGI::finalizeHeaders(Context *ctx)
{
    struct wsgi_request *wsgi_req = static_cast<wsgi_request*>(ctx->request()->engineData());
    Response *res = ctx->res();

    QByteArray status = statusCode(res->status());
    if (uwsgi_response_prepare_headers(wsgi_req,
                                       status.data(),
                                       status.size())) {
        return false;
    }

    if (!Engine::finalizeHeaders(ctx)) {
        return false;
    }

    const Headers headers = res->headers();
    auto it = headers.constBegin();
    auto endIt = headers.constEnd();
    while (it != endIt) {
        QByteArray key = camelCaseHeader(it.key()).toLatin1();
        QByteArray value = it.value().toLatin1();

        if (uwsgi_response_add_header(wsgi_req,
                                      key.data(),
                                      key.size(),
                                      value.data(),
                                      value.size())) {
            return false;
        }

        ++it;
    }

    return true;
}
示例#19
0
    void getResponseHeaders(Headers& headers) {
        while (true) {
            istream line(input.readLine());
            Header newHeader;
            getline(line, newHeader.first, ':'); // Only read up until the ':'
            trim(newHeader.first);
            to_lower(newHeader.first);
            if (newHeader.first.empty())
                break;
            getline(line, newHeader.second); // Read the rest of the line
            trim(newHeader.second);
            headers.insert(newHeader);
        }

    }
示例#20
0
void RequestParser::parseHeaders(const Item& aItem, Headers& aHeaders)
{
  Item lKey;
  String lName;
  String lValue;

  zorba::Iterator_t lIterator = aItem.getObjectKeys();
  lIterator->open();

  while (lIterator->next(lKey))
  {
    lName = lKey.getStringValue();
    getString(aItem, lName, true, lValue);
    aHeaders.push_back(std::pair<String, String>(lName, lValue));
  }
  lIterator->close();
}
示例#21
0
void process_properties(Feature & feature, Headers const& headers, Values const& values, Locator const& locator, Transcoder const& tr)
{
    auto val_beg = values.begin();
    auto val_end = values.end();
    auto num_headers = headers.size();
    for (std::size_t i = 0; i < num_headers; ++i)
    {
        std::string const& fld_name = headers.at(i);
        if (val_beg == val_end)
        {
            feature.put(fld_name,tr.transcode(""));
            continue;
        }
        std::string value = mapnik::util::trim_copy(*val_beg++);
        int value_length = value.length();

        if (locator.index == i && (locator.type == geometry_column_locator::WKT
                                   || locator.type == geometry_column_locator::GEOJSON)  ) continue;


        bool matched = false;
        bool has_dot = value.find(".") != std::string::npos;
        if (value.empty() ||
            (value_length > 20) ||
            (value_length > 1 && !has_dot && value[0] == '0'))
        {
            matched = true;
            feature.put(fld_name,std::move(tr.transcode(value.c_str())));
        }
        else if (csv_utils::is_likely_number(value))
        {
            bool has_e = value.find("e") != std::string::npos;
            if (has_dot || has_e)
            {
                double float_val = 0.0;
                if (mapnik::util::string2double(value,float_val))
                {
                    matched = true;
                    feature.put(fld_name,float_val);
                }
            }
            else
            {
                mapnik::value_integer int_val = 0;
                if (mapnik::util::string2int(value,int_val))
                {
                    matched = true;
                    feature.put(fld_name,int_val);
                }
            }
        }
        if (!matched)
        {
            if (csv_utils::ignore_case_equal(value, "true"))
            {
                feature.put(fld_name, true);
            }
            else if (csv_utils::ignore_case_equal(value, "false"))
            {
                feature.put(fld_name, false);
            }
            else // fallback to string
            {
                feature.put(fld_name,std::move(tr.transcode(value.c_str())));
            }
        }
    }
}
示例#22
0
 void clear ()
 {
     myHead.clear();
     myBody.clear();
 }
示例#23
0
文件: headers.cpp 项目: tpatja/tufao
void HeadersTest::caseInsensitivity()
{
    QFETCH(QByteArray, qbytearray1);
    QFETCH(QByteArray, qbytearray2);

    const IByteArray ibytearray1 = IByteArray{qbytearray1.constData()};
    const IByteArray ibytearray2 = qbytearray2;

    Headers headers;
    headers.insert(ibytearray1, qbytearray2);
    headers.insert(ibytearray2, qbytearray2);

    QCOMPARE(headers.count(ibytearray1), 2);
    QCOMPARE(headers.count(ibytearray2), 2);

    QVERIFY(headers.values(ibytearray1)[0] == headers.values(ibytearray2)[1]);

    /* ====================================================================== */

    headers.clear();
    headers.insert(ibytearray1, qbytearray2);
    headers.replace(ibytearray1, qbytearray1);
    headers.insert(ibytearray2, qbytearray2);

    QCOMPARE(headers.count(ibytearray1), 2);
    QCOMPARE(headers.count(ibytearray2), 2);

    QVERIFY(headers.values(ibytearray1)[0] != headers.values(ibytearray2)[1]);
}
示例#24
0
 void addHeader( Header const & header )
 {
     assert( !fromCache() );
     includedHeaders_.insert( header );
 }
Uploads MultiPartFormDataParserPrivate::execute(char *buffer, int bufferSize)
{
    Uploads ret;
    QByteArray header;
    Headers headers;
    qint64 startOffset;
    int boundaryPos = 0;
    ParserState state = FindBoundary;

    while (!body->atEnd()) {
        qint64 len = body->read(buffer, bufferSize);
        int i = 0;
        while (i < len) {
            switch (state) {
            case FindBoundary:
                i += findBoundary(buffer + i, len - i, state, boundaryPos);
                break;
            case EndBoundaryCR:
                // TODO the "--" case
                if (buffer[i] != '\r') {
//                    qCDebug(CUTELYST_MULTIPART) << "EndBoundaryCR return!";
                    return ret;
                }
                state = EndBoundaryLF;
                break;
            case EndBoundaryLF:
                if (buffer[i] != '\n') {
//                    qCDebug(CUTELYST_MULTIPART) << "EndBoundaryLF return!";
                    return ret;
                }
                header.clear();
                state = StartHeaders;
                break;
            case StartHeaders:
//                qCDebug(CUTELYST_MULTIPART) << "StartHeaders" << body->pos() - len + i;
                if (buffer[i] == '\r') {
                    state = EndHeaders;
                } else if (buffer[i] == '-') {
//                    qCDebug(CUTELYST_MULTIPART) << "StartHeaders return!";
                    return ret;
                } else {
                    char *pch = strchr(buffer + i, '\r');
                    if (pch == NULL) {
                        header.append(buffer + i, len - i);
                        i = len;
                    } else {
                        header.append(buffer + i, pch - buffer - i);
                        i = pch - buffer;
                        state = FinishHeader;
                    }
                }
                break;
            case FinishHeader:
//                qCDebug(CUTELYST_MULTIPART) << "FinishHeader" << header;
                if (buffer[i] == '\n') {
                    int dotdot = header.indexOf(':');
                    headers.setHeader(QString::fromLatin1(header.left(dotdot)),
                                      QString::fromLatin1(header.mid(dotdot + 1).trimmed()));
                    header.clear();
                    state = StartHeaders;
                } else {
//                    qCDebug(CUTELYST_MULTIPART) << "FinishHeader return!";
                    return ret;
                }
                break;
            case EndHeaders:
//                qCDebug(CUTELYST_MULTIPART) << "EndHeaders";
                if (buffer[i] == '\n') {
                    state = StartData;
                } else {
//                    qCDebug(CUTELYST_MULTIPART) << "EndHeaders return!";
                    return ret;
                }
                break;
            case StartData:
//                qCDebug(CUTELYST_MULTIPART) << "StartData" << body->pos() - len + i;
                startOffset = body->pos() - len + i;
                state = EndData;
            case EndData:
                i += findBoundary(buffer + i, len - i, state, boundaryPos);
                if (state == EndBoundaryCR) {
//                    qCDebug(CUTELYST_MULTIPART) << "EndData" << body->pos() - len + i - boundaryLength - 1;
                    UploadPrivate *priv = new UploadPrivate(body);
                    priv->headers = headers;
                    headers.clear();
                    priv->startOffset = startOffset;
                    priv->endOffset = body->pos() - len + i - boundaryLength - 1;
                    ret << new Upload(priv);
                }
            }
            ++i;
        }
    }

    return ret;
}
示例#26
0
void uWSGI::processRequest(wsgi_request *req)
{
    CachedRequest *cache = static_cast<CachedRequest *>(req->async_environ);

    // wsgi_req->uri containg the whole URI it /foo/bar?query=null
    // so we use path_info, maybe it would be better to just build our
    // Request->uri() from it, but we need to run a performance test
    uint16_t pos = notSlash(req->path_info, req->path_info_len);
    const QString path = QString::fromLatin1(req->path_info + pos, req->path_info_len - pos);

    const QString serverAddress = QString::fromLatin1(req->host, req->host_len);
    const QByteArray query = QByteArray::fromRawData(req->query_string, req->query_string_len);

    const QString method = QString::fromLatin1(req->method, req->method_len);
    const QString protocol = QString::fromLatin1(req->protocol, req->protocol_len);
    const QString remoteAddress = QString::fromLatin1(req->remote_addr, req->remote_addr_len);
    const QString remoteUser = QString::fromLatin1(req->remote_user, req->remote_user_len);

    quint16 remotePort = 0;
    Headers headers;
    // we scan the table in reverse, as updated values are at the end
    for (int i = req->var_cnt - 1; i > 0; i -= 2) {
        struct iovec &name = req->hvec[i - 1];
        struct iovec &value = req->hvec[i];
        if (!uwsgi_startswith(static_cast<char *>(name.iov_base),
                              const_cast<char *>("HTTP_"), 5)) {
            headers.setHeader(QString::fromLatin1(static_cast<char *>(name.iov_base) + 5, name.iov_len - 5),
                              QString::fromLatin1(static_cast<char *>(value.iov_base), value.iov_len));
        } else if (!remotePort &&
                   !uwsgi_strncmp(const_cast<char *>("REMOTE_PORT"), 11,
                                  static_cast<char *>(name.iov_base), name.iov_len)) {
            remotePort = QByteArray::fromRawData(static_cast<char *>(value.iov_base), value.iov_len).toUInt();
        }
    }

    if (req->content_type_len > 0) {
        headers.setContentType(QString::fromLatin1(req->content_type, req->content_type_len));
    }

    if (req->encoding_len > 0) {
        headers.setContentEncoding(QString::fromLatin1(req->encoding, req->encoding_len));
    }

    QIODevice *body;
    if (req->post_file) {
//        qCDebug(CUTELYST_UWSGI) << "Post file available:" << req->post_file;
        QFile *upload = cache->bodyFile;
        if (upload->open(req->post_file, QIODevice::ReadOnly)) {
            body = upload;
        } else {
//            qCDebug(CUTELYST_UWSGI) << "Could not open post file:" << upload->errorString();
            body = cache->bodyBufferedUWSGI;
            body->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
        }
    } else if (uwsgi.post_buffering) {
//        qCDebug(CUTELYST_UWSGI) << "Post buffering size:" << uwsgi.post_buffering;
        body = cache->bodyUWSGI;
        body->reset();
    } else {
        // BodyBufferedUWSGI is an IO device which will
        // only consume the body when some of it's functions
        // is called, this is because here we can't seek
        // the body.
        body = cache->bodyBufferedUWSGI;
        body->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
    }

    Engine::processRequest(method,
                           path,
                           query,
                           protocol,
                           req->https_len,
                           serverAddress,
                           remoteAddress,
                           remotePort,
                           remoteUser,
                           headers,
                           req->start_of_request,
                           body,
                           req);

    body->close();
}
示例#27
0
/**
* @brief 
*
* @param request
*
* @return 
*/
bool RtspConnection::handleRequest( const std::string &request )
{
    Debug( 2, "Handling RTSP request: %s (%zd bytes)", request.c_str(), request.size() );

    StringTokenList lines( request, "\r\n" );
    if ( lines.size() <= 0 )
    {
        Error( "Unable to split request '%s' into tokens", request.c_str() );
        return( false );
    }

    StringTokenList parts( lines[0], " " );
    if ( parts.size() != 3 )
    {
        Error( "Unable to split request part '%s' into tokens", lines[0].c_str() );
        return( false );
    }

    std::string requestType = parts[0];
    Debug( 4, "Got request '%s'", requestType.c_str() );
    std::string requestUrl = parts[1];
    Debug( 4, "Got requestUrl '%s'", requestUrl.c_str() );
    std::string requestVer = parts[2];
    Debug( 4, "Got requestVer '%s'", requestVer.c_str() );
    if ( requestVer != "RTSP/1.0" )
    {
        Error( "Unexpected RTSP version '%s'", requestVer.c_str() );
        return( false );
    }

    // Extract headers from request
    Headers requestHeaders;
    for ( int i = 1; i < lines.size(); i++ )
    {
        StringTokenList parts( lines[i], ": " );
        if ( parts.size() != 2 )
        {
            Error( "Unable to split request header '%s' into tokens", lines[i].c_str() );
            return( false );
        }
        Debug( 4, "Got header '%s', value '%s'", parts[0].c_str(), parts[1].c_str() );
        requestHeaders.insert( Headers::value_type( parts[0], parts[1] ) );
    }

    if ( requestHeaders.find("CSeq") == requestHeaders.end() )
    {
        Error( "No CSeq header found" );
        return( false );
    }
    Debug( 4, "Got sequence number %s", requestHeaders["CSeq"].c_str() );

    uint32_t session = 0;
    if ( requestHeaders.find("Session") != requestHeaders.end() )
    {
        Debug( 4, "Got session header, '%s', passing to session", requestHeaders["Session"].c_str() );
        session = strtol( requestHeaders["Session"].c_str(), NULL, 16 );
    }

    Headers responseHeaders;
    responseHeaders.insert( Headers::value_type( "CSeq", requestHeaders["CSeq"] ) );
    if ( requestType == "OPTIONS" )
    {
        responseHeaders.insert( Headers::value_type( "Public", "DESCRIBE, SETUP, PLAY, GET_PARAMETER, TEARDOWN" ) );
        return( sendResponse( responseHeaders ) );
    }
    else if ( requestType == "DESCRIBE" )
    {
        FeedProvider *provider = validateRequestUrl( requestUrl );

        if ( !provider )
        {
            sendResponse( responseHeaders, "", 404, "Not Found" );
            return( false );
        }

        const VideoProvider *videoProvider = dynamic_cast<const VideoProvider *>(provider);

        int codec = AV_CODEC_ID_MPEG4;
        int width = videoProvider->width();
        int height = videoProvider->height();
        FrameRate frameRate = 15;
        //FrameRate frameRate = videoProvider->frameRate();
        int bitRate = 90000;
        int quality = 70;

        std::string sdpFormatString =
            "v=0\r\n"
            "o=- %jd %jd IN IP4 %s\r\n"
            "s=ZoneMinder Stream\r\n"
            "i=Media Streamers\r\n"
            "c=IN IP4 0.0.0.0\r\n"
            "t=0 0\r\n"
            "a=control:*\r\n"
            "a=range:npt=0.000000-\r\n";
        uint64_t now64 = time64();
        char hostname[HOST_NAME_MAX] = "";
        if ( gethostname( hostname, sizeof(hostname) ) < 0 )
            Fatal( "Can't gethostname: %s", strerror(errno) );

        std::string sdpString = stringtf( sdpFormatString, now64, now64, hostname );

        if ( codec == AV_CODEC_ID_H264 )
        {
            if ( provider->cl4ss() == "RawH264Input" )
            {
                std::string encoderKey = H264Relay::getPoolKey( provider->identity(), width, height, frameRate, bitRate, quality );
                if ( !(mEncoder = Encoder::getPooledEncoder( encoderKey )) )
                {
                    H264Relay *h264Relay = NULL;
                    mEncoder = h264Relay = new H264Relay( provider->identity(), width, height, frameRate, bitRate, quality );
                    mEncoder->registerProvider( *provider );
                    Encoder::poolEncoder( mEncoder );
                    h264Relay->start();
                }
                sdpString += mEncoder->sdpString( 1 ); // XXX - Should be variable
                responseHeaders.insert( Headers::value_type( "Content-length", stringtf( "%zd", sdpString.length() ) ) );
            }
            else
            {
                std::string encoderKey = H264Encoder::getPoolKey( provider->identity(), width, height, frameRate, bitRate, quality );
                if ( !(mEncoder = Encoder::getPooledEncoder( encoderKey )) )
                {
                    H264Encoder *h264Encoder = NULL;
                    mEncoder = h264Encoder = new H264Encoder( provider->identity(), width, height, frameRate, bitRate, quality );
                    mEncoder->registerProvider( *provider );
                    Encoder::poolEncoder( mEncoder );
                    h264Encoder->start();
                }
                sdpString += mEncoder->sdpString( 1 ); // XXX - Should be variable
                responseHeaders.insert( Headers::value_type( "Content-length", stringtf( "%zd", sdpString.length() ) ) );
            }
        }
        else if ( codec == AV_CODEC_ID_MPEG4 )
        {
            std::string encoderKey = MpegEncoder::getPoolKey( provider->identity(), width, height, frameRate, bitRate, quality );
            if ( !(mEncoder = Encoder::getPooledEncoder( encoderKey )) )
            {
                MpegEncoder *mpegEncoder = NULL;
                mEncoder = mpegEncoder = new MpegEncoder( provider->identity(), width, height, frameRate, bitRate, quality );
                mEncoder->registerProvider( *provider );
                Encoder::poolEncoder( mEncoder );
                mpegEncoder->start();
            }
            sdpString += mEncoder->sdpString( 1 ); // XXX - Should be variable
            responseHeaders.insert( Headers::value_type( "Content-length", stringtf( "%zd", sdpString.length() ) ) );
        }
        return( sendResponse( responseHeaders, sdpString ) );
    }
    else if ( requestType == "SETUP" )
    {
        // These commands are handled by RTSP session so pass them on and send any required responses
        RtspSession *rtspSession = 0;
        if ( session )
        {
            rtspSession = mRtspController->getSession( session );
        }
        else
        {
            rtspSession = mRtspController->newSession( this, mEncoder );
        }
        if ( rtspSession->recvRequest( requestType, requestUrl, requestHeaders, responseHeaders ) )
            return( sendResponse( responseHeaders ) );
        return( false );
    }
    else if ( requestType == "PLAY" || requestType == "GET_PARAMETER" || requestType == "TEARDOWN" )
    {
        // These commands are handled by RTSP session so pass them on and send any required responses
        RtspSession *rtspSession = 0;
        if ( session )
        {
            rtspSession = mRtspController->getSession( session );
            if ( rtspSession && rtspSession->recvRequest( requestType, requestUrl, requestHeaders, responseHeaders ) )
                return( sendResponse( responseHeaders ) );
        }
        return( sendResponse( responseHeaders, "", 454, "Session Not Found" ) );
    }
    Error( "Unrecognised RTSP command '%s'", requestType.c_str() );
    return( sendResponse( responseHeaders, "", 405, "Method not implemented" ) );
}
示例#28
0
bool containsHeader(const Headers& headers, const std::string& name)
{
   return findHeader(headers, name) != headers.end();
}
示例#29
0
int main(int argc, char *argv[])
{
	// Parse command line arguments.
	boost::filesystem::path output(".");
	if (argc >= 2) output = argv[1];

	// Create the output directory if required.
	if (!boost::filesystem::exists(output)) {
		cout << "Creating output directory " << output << '\n';
		boost::filesystem::create_directories(output);
	}

	// Build the AST.
	Builder builder;
	buildAST(builder);

	// Determine implemented interfaces and child nodes.
	determineImplementedInterfaces(builder);
	determineChildNodes(builder);

	// Generate the code for the nodes.
	Headers headerFileNames;
	Headers sourceFileNames;
	for (Builder::Nodes::iterator it = builder.nodes.begin(); it != builder.nodes.end(); it++) {
		const std::string &name = it->first;
		Node &node = it->second;
		//cout << "- Generating \033[36;1m" << name << "\033[0m" << '\n';
		std::string headerName = name + ".hpp";
		std::string sourceName = name + ".cpp";

		// Generate the header and source file.
		boost::filesystem::path hpath = output, spath = output;
		hpath /= headerName;
		spath /= sourceName;
		std::ofstream h(hpath.c_str());
		std::ofstream s(spath.c_str());

		h << "/* Automatically generated by ast-gen. DO NOT MODIFY. */\n";
		h << "#pragma once\n";
		h << "#include \"maxwell/ast/Node.hpp\"\n";
		h << "#include \"maxwell/ast/nodes/interfaces.hpp\"\n";
		h << "#include \"maxwell/ast/nodes/types.hpp\"\n";
		if (node.parent != "Node") h << "#include \"maxwell/ast/nodes/" << node.parent << ".hpp\"\n";
		h << '\n';

		s << "/* Automatically generated by ast-gen. DO NOT MODIFY. */\n";
		s << "#include \"maxwell/ast/nodes/" << headerName << "\"\n";
		s << "#include \"maxwell/ast/Coder.hpp\"\n";
		s << "#include <cstdio>\n";
		s << "#include <sstream>\n";
		s << "#include <stdexcept>\n";
		s << "using ast::" << name << ";\n";
		s << "using ast::NodePtr;\n";
		s << "using ast::NodeVector;\n\n";

		h << "namespace ast {\n\n";
		h << "class Encoder;\n";
		h << "class Decoder;\n\n";
		h << "class " << name << " : public Node\n{\npublic:\n";

		// Generate the constructor.
		h << "\t// constructor\n";
		h << "\t" << name << "();\n\n";
		s << name << "::" << name << "() : Node()";
		for (Node::Interfaces::iterator it = node.interfaces.begin(); it != node.interfaces.end(); it++) {
			const Node& intf = **it;
			s << ",\n\tinterface" << intf.name << "(this)";
		}
		s << " {}\n\n";

		// Generate auxiliary functions.
		h << "\t// auxiliary functions\n";
		h << "\tvirtual bool isKindOf(Kind k);\n";
		h << "\tvirtual bool implements(Interface i);\n";
		h << "\tvirtual std::string getClassName() const { return \"" << node.name << "\"; }\n";
		h << "\tvirtual NodePtr copy();\n";
		h << "\tvirtual bool equalTo(const NodePtr& o);\n";
		h << "\tvirtual std::string describe(int depth = -1);\n";
		h << '\n';

		// isKindOf
		s << "bool " << name << "::isKindOf(Kind k) {\n";
		s << "\tif (" << node.parent << "::isKindOf(k)) return true;\n";
		s << "\treturn k == k" << node.name << ";\n";
		s << "}\n\n";

		// implements
		s << "bool " << name << "::implements(Interface i) {\n";
		s << "\tif (" << node.parent << "::implements(i)) return true;\n";
		for (Node::Interfaces::iterator it = node.interfaces.begin(); it != node.interfaces.end(); it++) {
			const Node& intf = **it;
			s << "\tif (i == k" << intf.intfName << ") return true;\n";
		}
		s << "\treturn false;\n";
		s << "}\n\n";

		// copy
		s << "NodePtr " << name << "::copy() {\n";
		s << "\tPtr c (new " << name << ");\n";
		for (Node::Fields::iterator f = node.attributes.begin(); f != node.attributes.end(); f++) {
			s << "\tNode::copy(this->" << (*f).name << ", c->" << (*f).name << ");\n";
		}
		s << "\treturn c;\n";
		s << "}\n\n";

		// equalTo
		s << "bool " << name << "::equalTo(const NodePtr& o) {\n";
		s << "\tconst shared_ptr<" << node.name << ">& other = boost::dynamic_pointer_cast<" << node.name << ">(o);\n";
		s << "\tif (!other) return false;\n";
		for (Node::Fields::iterator fit = node.attributes.begin(); fit != node.attributes.end(); fit++) {
			Node::Field& f = *fit;
			s << "\tif (!equal(this->" << f.name << ", other->" << f.name << ")) return false;\n";
		}
		s << "\treturn true;\n";
		s << "}\n\n";

		// describe
		s << "std::string " << name << "::describe(int depth) {\n";
		s << "\tstd::stringstream str, b;\n";
		if (node.descriptionBody.empty()) {
			s << "\tif (depth == 0) return \"" << name << "{…}\";\n";
			s << "\tstr << \"" << name << "{\";\n";
			for (Node::Fields::iterator fit = node.attributes.begin(); fit != node.attributes.end(); fit++) {
				Node::Field& f = *fit;

				// Don't print empty strings and arrays.
				s << "\t";
				if (f.isString || f.isArray) s << "if (!this->" <<f.name<< ".empty()) ";
				if (f.isNode) s << "if (this->" << f.name << ") ";

				// Print the field name.
				s << "b << \"\\n  \\033[1m" << f.name << "\\033[0m = ";

				// Print the actual data.
				if (f.isString) s << "\\033[33m\\\"\" << this->" << f.name << " << \"\\\"\\033[0m\";";
				if (f.isBool) s << "\\033[34m\" << (this->" << f.name << " ? \"true\" : \"false\") << \"\\033[0m\";";
				if (f.isInt) s << "\\033[35m\" << this->" << f.name << " << \"\\033[0m\";";
				if (f.isNode) {
					if (f.ref) {
						s << "\\033[36m\" << this->" << f.name << ".id << \"\\033[0m\";";
					} else {
						s << "\" << indent(this->" << f.name << "->describe(depth-1));";
					}
				}
				if (f.isArray) s << "\" << indent(describeVector(this->" << f.name << ", depth-1));";
				s << "\n";
			}
			s << "\tstring bs = b.str();\n";
			s << "\tif (!bs.empty()) str << bs << '\\n';\n";
			s << "\tstr << \"}\";\n";
		} else {
			string body(node.descriptionBody);
			boost::algorithm::replace_all(body, "\n", "\n\t\t");
			s << "\t" << body << "\n";
		}
		s << "\treturn str.str();\n";
		s << "}\n\n";
		s << '\n';

		// Generate the accessor functions.
		h << "\t// accessor functions\n";
		for (Node::Fields::iterator fit = node.attributes.begin(); fit != node.attributes.end(); fit++) {
			Node::Field& f = *fit;
			string ref = "const " + f.cpp_type + "&";
			string upper = f.name;
			if (!upper.empty()) upper[0] = toupper(upper[0]);
			h << "\tvoid set" << upper << "(" << ref << " v);\n";
			s << "void " << name << "::set" << upper << "(" << ref << " v) {\n";

			vector<string> ifcomponents;
			string allowedNodes;
			string allowedInterfaces;
			for (unsigned i = 0; i < f.allowedNodes.size(); i++) {
				ifcomponents.push_back("!v->isKindOf(k" + f.allowedNodes[i] + ")");
				if (!allowedNodes.empty()) allowedNodes += ", ";
				allowedNodes += f.allowedNodes[i];
			}
			for (unsigned i = 0; i < f.allowedInterfaces.size(); i++) {
				ifcomponents.push_back("!v->implements(k" + builder.interfaces[f.allowedInterfaces[i]].intfName + ")");
				if (!allowedInterfaces.empty()) allowedInterfaces += ", ";
				allowedInterfaces += f.allowedInterfaces[i];
			}
			if (!ifcomponents.empty()) {
				s << "\tif (v";
				for (unsigned i = 0; i < ifcomponents.size(); i++) {
					s << " && " << ifcomponents[i];
				}
				s << ") {\n";
				s << "\t\tthrow std::runtime_error(\"'" << f.name << "' of \" + id.str() + \" needs to be of kind {" << allowedNodes << "} or implement interface {" << allowedInterfaces << "}, got \" + v->getClassName() + \" (\" + v->getId().str() + \") instead.\");\n";
				s << "\t}\n";
			}

			if (f.ref) {
				s << "\tif (!v && " << f.name << ") {\n";
				s << "\t\tmodify(\"" << f.name << "\");\n";
				s << "\t\t" << f.name << ".reset();\n";
				s << "\t}\n";
				s << "\tif (!" << f.name << " || v->getId() != " << f.name << ".id) {\n";
			} else {
				s << "\tif (!equal(v, " << f.name << ")) {\n";
			}
			s << "\t\tmodify(\"" << f.name << "\");\n";
			if (f.ref) {
				s << "\t\t" << f.name << ".set(v);\n";
			} else {
				s << "\t\t" << f.name << " = v;\n";
			}
			s << "\t}\n";
			s << "}\n\n";

			// special setter for references
			if (f.ref) {
				h << "\tvoid set" << upper << "(const NodeId& v);\n";
				s << "void " << name << "::set" << upper << "(const NodeId& v) {\n";
				s << "\tif (v != " << f.name << ".id) {\n";
				s << "\t\tmodify(\"" << f.name << "\");\n";
				s << "\t\t" << f.name << ".set(v);\n";
				s << "\t}\n";
				s << "}\n\n";
			}

			h << "\t" << ref << " get" << upper << "(bool required = true);\n\n";
			s << ref << " " << name << "::get" << upper << "(bool required) {\n";
			s << "\tconst " << f.cpp_type << "& v = ";
			if (f.ref) {
				s << f.name << ".get(repository);\n";
			} else {
				s << f.name << ";\n";
			}
			if (f.isNode) {
				s << "\tif (required && !v) {\n";
				s << "\t\tthrow std::runtime_error(\"Node \" + getId().str() + \" is required to have " << f.name << " set to a non-null value.\");\n";
				s << "\t}\n";
			} else if (f.isString) {
				s << "\tif (required && v.empty()) {\n";
				s << "\t\tthrow std::runtime_error(\"Node \" + getId().str() + \" is required to have a non-empty string " << f.name << " set.\");\n";
				s << "\t}\n";
			}
			s << "\treturn v;\n";
			s << "}\n\n\n";
		}

		// Generate the encode() and decode() function.
		h << "\t// encoding and decoding\n";
		h << "\tvirtual void encode(Encoder& e);\n";
		h << "\tvirtual void decode(Decoder& d);\n";
		h << '\n';

		s << "void " << name << "::encode(Encoder& e) {\n";
		s << "\te.encode(this->range);\n";
		s << "\te.encode(this->referenceRange);\n";
		for (Node::Fields::iterator f = node.attributes.begin(); f != node.attributes.end(); f++) {
			s << "\te.encode(this->" << (*f).name << ");\n";
		}
		s << "}\n\n";

		s << "void " << name << "::decode(Decoder& d) {\n";
		s << "\td.decode(this->range);\n";
		s << "\td.decode(this->referenceRange);\n";
		for (Node::Fields::iterator f = node.attributes.begin(); f != node.attributes.end(); f++) {
			s << "\td.decode(this->" << (*f).name << ");\n";
		}
		s << "}\n\n";
		s << '\n';

		// Generate the hierarchy functions.
		h << "\t// hierarchy functions\n";
		h << "\tvirtual void updateHierarchyOfChildren();\n";
		h << "\tvirtual const NodePtr& resolvePath(const std::string& path);\n";

		// updateHierarchy
		s << "void " << name << "::updateHierarchyOfChildren() {\n";
		for (Node::Fields::iterator fit = node.attributes.begin(); fit != node.attributes.end(); fit++) {
			Node::Field& f = *fit;
			if (f.isNode && !f.ref) {
				s << "\tif (this->"<<f.name<<") this->"<<f.name<<"->updateHierarchy(id + \""<<f.name<<"\", repository, this);\n";
			} else if (f.isNodeArray) {
				s << "\tfor (unsigned i = 0; i < this->"<<f.name<<".size(); i++) {\n";
				s << "\t\tchar buf[32]; snprintf(buf, 31, \"%i\", i);\n";
				s << "\t\tthis->"<<f.name<<"[i]->updateHierarchy((id + \""<<f.name<<"\") + buf, repository, this);\n";
				s << "\t}\n";
			}
		}
		s << "}\n\n";

		// resolvePath
		s << "const NodePtr& " << name << "::resolvePath(const std::string& path) {\n";
		FieldNames fields, arrayFields;
		for (Node::Fields::iterator fit = node.attributes.begin(); fit != node.attributes.end(); fit++) {
			Node::Field& f = *fit;
			if (f.isNode) {
				fields.insert(f.name);
			} else if (f.isNodeArray) {
				fields.insert(f.name);
				arrayFields.insert(f.name);
			}
		}
		if (!fields.empty()) {
			s << "\tsize_t size = path.size();\n";
			generateResolvePathBody(s, fields, arrayFields, 1);
		}
		s << "\tthrow std::runtime_error(\"Node path '\" + path + \"' does not point to a node or array of nodes.\");\n";
		s << "}\n\n";

		// getChildren
		if (!node.children.empty()) {
			h << "\tvirtual NodeVector getChildren();\n";
			s << "NodeVector " << name << "::getChildren() {\n";
			s << "\tNodeVector v;\n";
			for (Node::Children::iterator c = node.children.begin(); c != node.children.end(); c++) {
				Node::Field& f = **c;
				if (f.isNode) {
					string upper = (char)toupper(f.name[0]) + f.name.substr(1);
					s << "\tif (const NodePtr& n = this->get" << upper << "(false)) v.push_back(n);\n";
				} else if (f.isArray) {
					s << "\tv.insert(v.end(), this->" << f.name << ".begin(), this->" << f.name << ".end());\n";
				}
			}
			s << "\treturn v;\n";
			s << "}\n\n";
		}
		h << '\n';

		// Generate the interface accessors.
		if (!node.interfaces.empty()) {
			h << "\t// interfaces\n";
			for (Node::Interfaces::iterator it = node.interfaces.begin(); it != node.interfaces.end(); it++) {
				const Node& intf = **it;
				h << "\tvirtual " << intf.intfName << "* as" << intf.name << "() { return &this->interface" << intf.name << "; }\n";
			}
			h << "\n";
		}

		// Generate boost::shared_ptr convenience typedef.
		h << "\t// shared_ptr convenience\n";
		h << "\ttypedef boost::shared_ptr<" << node.name << "> Ptr;\n";
		h << "\ttemplate<typename T> static Ptr from(const T& n) { return boost::dynamic_pointer_cast<" << node.name << ">(n); }\n";
		h << "\ttemplate<typename T> static Ptr needFrom(const T& n) {\n";
		h << "\t\tPtr r = boost::dynamic_pointer_cast<" << node.name << ">(n);\n";
		h << "\t\tif (!r)\n";
		h << "\t\t\tthrow std::runtime_error(\"Node \" + n->getId().str() + \" (a \" + n->getClassName() + \") cannot be dynamically cast to " << node.name << ".\");\n";
		h << "\t\treturn r;\n";
		h << "\t}\n";
		h << '\n';

		h << "protected:\n";
		for (Node::Fields::iterator f = node.attributes.begin(); f != node.attributes.end(); f++) {
			if ((*f).ref) {
				h << "\tNodeRef " << (*f).name << ";\n";
			} else {
				h << "\t" << (*f).cpp_type << " " << (*f).name << ";\n";
			}
		}
		if (!node.interfaces.empty()) {
			h << "\n\t// interfaces\n";
			for (Node::Interfaces::iterator it = node.interfaces.begin(); it != node.interfaces.end(); it++) {
				const Node& intf = **it;
				h << "\t" << intf.intfName << "Impl<" << node.name << "> interface" << intf.name << ";\n";
			}
		}

		h << "};\n\n";
		h << "} // namespace ast\n";
		headerFileNames.push_back(headerName);
		sourceFileNames.push_back(sourceName);
	}

	// Generate the header file containing general typedefs.
	makeTypesHeader(output, builder);
	makeNodesHeader(output, builder, headerFileNames);
	makeInterfacesHeader(output, builder);

	// Generate the base header file for ast::Node which implements default interface accessors.
	makeBaseNodeHeader(output, builder);

	// Generate the header file aggregating all AST things.
	boost::filesystem::path ahpath = output;
	ahpath /= "ast.hpp";
	ofstream ah(ahpath.c_str());
	ah << "/* Automatically generated by ast-gen. DO NOT MODIFY. */\n";
	ah << "#pragma once\n\n";
	ah << "#include \"maxwell/ast/nodes/types.hpp\"\n";
	ah << "#include \"maxwell/ast/nodes/nodes.hpp\"\n";
	ah << "#include \"maxwell/ast/nodes/interfaces.hpp\"\n";

	return 0;
}