Exemplo n.º 1
0
    ResponseStatus NetworkInterfaceImpl::runCommand(
            const ReplicationExecutor::RemoteCommandRequest& request) {

        try {
            BSONObj output;

            StatusWith<int> timeoutStatus = getTimeoutMillis(request.expirationDate, now());
            if (!timeoutStatus.isOK())
                return ResponseStatus(timeoutStatus.getStatus());

            int timeout = timeoutStatus.getValue();
            Timer timer;
            ScopedDbConnection conn(request.target.toString(), timeout);
            conn->runCommand(request.dbname, request.cmdObj, output);
            conn.done();
            return ResponseStatus(Response(output, Milliseconds(timer.millis())));
        }
        catch (const DBException& ex) {
            return ResponseStatus(ex.toStatus());
        }
        catch (const std::exception& ex) {
            return ResponseStatus(
                    ErrorCodes::UnknownError,
                    mongoutils::str::stream() <<
                    "Sending command " << request.cmdObj << " on database " << request.dbname <<
                    " over network to " << request.target.toString() << " received exception " <<
                    ex.what());
        }
    }
Exemplo n.º 2
0
static void
processDataFromClient(TConn *      const connectionP,
                      abyss_bool   const lastReqOnConn,
                      abyss_bool * const keepAliveP) {

    TSession session;

    RequestInit(&session, connectionP);

    session.serverDeniesKeepalive = lastReqOnConn;
        
    RequestRead(&session);
    if (session.status == 0) {
        if (session.version.major >= 2)
            ResponseStatus(&session, 505);
        else if (!RequestValidURI(&session))
            ResponseStatus(&session, 400);
        else
            runUserHandler(&session, connectionP->server->srvP);
    }
    assert(session.status != 0);
    
    if (session.responseStarted)
        HTTPWriteEndChunk(&session);
    else
        ResponseError(&session);

    *keepAliveP = HTTPKeepalive(&session);
    
    SessionLog(&session);

    RequestFree(&session);
}
Exemplo n.º 3
0
static void
sendFileAsResponse(TSession *const sessionP,
                   TFile *const fileP,
                   const char *const fileName,
                   time_t const fileModTime,
                   MIMEType *const mimeTypeP) {

    uint64_t const filesize = FileSize(fileP);
    const char *const mediatype = MIMETypeGuessFromFile2(mimeTypeP, fileName);

    uint64_t start;  /* Defined only if session has one range */
    uint64_t end;    /* Defined only if session has one range */

    switch (sessionP->ranges.size) {
        case 0:
            ResponseStatus(sessionP, 200);
            break;

        case 1: {
            bool decoded;
            decoded = RangeDecode((char *) (sessionP->ranges.item[0]), filesize,
                                  &start, &end);
            if (!decoded) {
                ListFree(&sessionP->ranges);
                ResponseStatus(sessionP, 200);
            } else {
                const char *contentRange;
                xmlrpc_asprintf(&contentRange,
                                "bytes %" PRIu64 "-%" PRIu64 "/%" PRIu64,
                                start, end, filesize);
                ResponseAddField(sessionP, "Content-range", contentRange);
                xmlrpc_strfree(contentRange);

                ResponseContentLength(sessionP, end - start + 1);
                ResponseStatus(sessionP, 206);
            }
        }
            break;

        default:
            ResponseContentType(sessionP,
                                "multipart/ranges; boundary=" BOUNDARY);
            ResponseStatus(sessionP, 206);
            break;
    }

    if (sessionP->ranges.size == 0) {
        ResponseContentLength(sessionP, filesize);
        ResponseContentType(sessionP, mediatype);
    }

    addLastModifiedHeader(sessionP, fileModTime);

    ResponseWriteStart(sessionP);

    if (sessionP->requestInfo.method != m_head)
        sendBody(sessionP, fileP, filesize, mediatype, start, end);
}
Exemplo n.º 4
0
static void
handleDirectory(TSession *const sessionP,
                const char *const dirName,
                time_t const fileModTime,
                MIMEType *const mimeTypeP) {

    bool text;
    bool ascending;
    uint16_t sort;    /* 1=by name, 2=by date */
    const char *error;

    determineSortType(sessionP->requestInfo.query,
                      &ascending, &sort, &text, &error);

    if (error) {
        ResponseStatus(sessionP, 400);
        xmlrpc_strfree(error);
    } else if (notRecentlyModified(sessionP, fileModTime)) {
        ResponseStatus(sessionP, 304);
        ResponseWriteStart(sessionP);
    } else {
        TPool pool;
        bool succeeded;
        succeeded = PoolCreate(&pool, 1024);
        if (!succeeded)
            ResponseStatus(sessionP, 500);
        else {
            TList list;
            uint16_t responseStatus;
            const char *error;
            generateListing(&list, dirName, sessionP->requestInfo.uri,
                            &pool, &error, &responseStatus);
            if (error) {
                ResponseStatus(sessionP, responseStatus);
                xmlrpc_strfree(error);
            } else {
                ResponseStatus(sessionP, 200);
                ResponseContentType(sessionP,
                                    text ? "text/plain" : "text/html");

                addLastModifiedHeader(sessionP, fileModTime);

                ResponseChunked(sessionP);
                ResponseWriteStart(sessionP);

                if (sessionP->requestInfo.method != m_head)
                    sendDirectoryDocument(&list, ascending, sort, text,
                                          sessionP->requestInfo.uri, mimeTypeP,
                                          sessionP);

                HTTPWriteEndChunk(sessionP);

                ListFree(&list);
            }
            PoolFree(&pool);
        }
    }
}
Exemplo n.º 5
0
 bool NetworkInterfaceMockWithMap::addResponse(
         const ReplicationExecutor::RemoteCommandRequest& request,
         const StatusWith<BSONObj>& response,
         bool isBlocked) {
     boost::lock_guard<boost::mutex> lk(_mutex);
     return _responses.insert(std::make_pair(request,
                                             BlockableResponseStatus(
                                                  !response.isOK() ?
                                                         ResponseStatus(response.getStatus()) :
                                                         ResponseStatus(Response(
                                                                            response.getValue(),
                                                                            Milliseconds(0)))
                                                  , isBlocked))).second;
 }
Exemplo n.º 6
0
abyss_bool
RequestAuth(TSession *r,char *credential,char *user,char *pass) {

    char *p,*x;
    char z[80],t[80];

    p=RequestHeaderValue(r,"authorization");
    if (p) {
        NextToken((const char **)&p);
        x=GetToken(&p);
        if (x) {
            if (strcasecmp(x,"basic")==0) {
                NextToken((const char **)&p);
                sprintf(z,"%s:%s",user,pass);
                Base64Encode(z,t);

                if (strcmp(p,t)==0) {
                    r->request_info.user=strdup(user);
                    return TRUE;
                };
            };
        }
    };

    sprintf(z,"Basic realm=\"%s\"",credential);
    ResponseAddField(r,"WWW-Authenticate",z);
    ResponseStatus(r,401);
    return FALSE;
}
ResponseStatus NetworkInterfaceASIO::_responseFromMessage(const Message& received,
                                                          rpc::Protocol protocol) {
    try {
        // TODO: elapsed isn't going to be correct here, SERVER-19697
        auto start = now();
        auto reply = rpc::makeReply(&received);

        if (reply->getProtocol() != protocol) {
            auto requestProtocol = rpc::toString(static_cast<rpc::ProtocolSet>(protocol));
            if (!requestProtocol.isOK())
                return requestProtocol.getStatus();

            return Status(ErrorCodes::RPCProtocolNegotiationFailed,
                          str::stream() << "Mismatched RPC protocols - request was '"
                                        << requestProtocol.getValue().toString() << "' '"
                                        << " but reply was '" << opToString(received.operation())
                                        << "'");
        }

        // unavoidable copy
        auto ownedCommandReply = reply->getCommandReply().getOwned();
        auto ownedReplyMetadata = reply->getMetadata().getOwned();
        return ResponseStatus(
            RemoteCommandResponse(ownedCommandReply, ownedReplyMetadata, now() - start));
    } catch (...) {
        // makeReply can throw if the reply was invalid.
        return exceptionToStatus();
    }
}
Exemplo n.º 8
0
static void
handleFile(TSession *const sessionP,
           const char *const fileName,
           time_t const fileModTime,
           MIMEType *const mimeTypeP) {
/*----------------------------------------------------------------------------
   This is an HTTP request handler for a GET.  It does the classic
   web server thing: send the file named in the URL to the client.
-----------------------------------------------------------------------------*/
    TFile *fileP;
    bool success;

    success = FileOpen(&fileP, fileName, O_BINARY | O_RDONLY);
    if (!success)
        ResponseStatusErrno(sessionP);
    else {
        if (notRecentlyModified(sessionP, fileModTime)) {
            ResponseStatus(sessionP, 304);
            ResponseWriteStart(sessionP);
        } else
            sendFileAsResponse(sessionP, fileP,
                               fileName, fileModTime, mimeTypeP);

        FileClose(fileP);
    }
}
Exemplo n.º 9
0
static void
handleReqInvalidURI(TSession * const sessionP) {

    ResponseStatus(sessionP, 400);

    ResponseError2(sessionP, "Invalid URI");
}
Exemplo n.º 10
0
void NetworkInterfaceMock::shutdown() {
    invariant(!inShutdown());

    stdx::unique_lock<stdx::mutex> lk(_mutex);
    invariant(_hasStarted);
    _inShutdown.store(true);
    NetworkOperationList todo;
    todo.splice(todo.end(), _scheduled);
    todo.splice(todo.end(), _unscheduled);
    todo.splice(todo.end(), _processing);
    todo.splice(todo.end(), _blackHoled);

    const Date_t now = _now_inlock();
    _waitingToRunMask |= kExecutorThread;  // Prevents network thread from scheduling.
    lk.unlock();
    for (NetworkOperationIterator iter = todo.begin(); iter != todo.end(); ++iter) {
        iter->setResponse(
            now, ResponseStatus(ErrorCodes::ShutdownInProgress, "Shutting down mock network"));
        iter->finishResponse();
    }
    lk.lock();
    invariant(_currentlyRunning == kExecutorThread);
    _currentlyRunning = kNoThread;
    _waitingToRunMask = kNetworkThread;
    _shouldWakeNetworkCondition.notify_one();
}
Exemplo n.º 11
0
bool
RequestAuth(TSession *   const sessionP,
            const char * const credential,
            const char * const user,
            const char * const pass) {
/*----------------------------------------------------------------------------
   Authenticate requester, in a very simplistic fashion.

   If the request executing on session *sessionP specifies basic
   authentication (via Authorization header) with username 'user', password
   'pass', then return TRUE.  Else, return FALSE and set up an authorization
   failure response (HTTP response status 401) that says user must supply an
   identity in the 'credential' domain.

   When we return TRUE, we also set the username in the request info for the
   session to 'user' so that a future SessionGetRequestInfo can get it.
-----------------------------------------------------------------------------*/
    bool authorized;
    char * authHdrPtr;

    authHdrPtr = RequestHeaderValue(sessionP, "authorization");
    if (authHdrPtr) {
        const char * authType;
        NextToken((const char **)&authHdrPtr);
        GetTokenConst(&authHdrPtr, &authType);
        authType = GetToken(&authHdrPtr);
        if (authType) {
            if (xmlrpc_strcaseeq(authType, "basic")) {
                const char * userPass;
                char userPassEncoded[80];

                NextToken((const char **)&authHdrPtr);

                xmlrpc_asprintf(&userPass, "%s:%s", user, pass);
                xmlrpc_base64Encode(userPass, userPassEncoded);
                xmlrpc_strfree(userPass);

                if (xmlrpc_streq(authHdrPtr, userPassEncoded)) {
                    sessionP->requestInfo.user = strdup(user);
                    authorized = TRUE;
                } else
                    authorized = FALSE;
            } else
                authorized = FALSE;
        } else
            authorized = FALSE;
    } else
        authorized = FALSE;

    if (!authorized) {
        const char * hdrValue;
        xmlrpc_asprintf(&hdrValue, "Basic realm=\"%s\"", credential);
        ResponseAddField(sessionP, "WWW-Authenticate", hdrValue);

        xmlrpc_strfree(hdrValue);

        ResponseStatus(sessionP, 401);
    }
    return authorized;
}
Exemplo n.º 12
0
static void
sendError(TSession *   const abyssSessionP,
          unsigned int const status) {
/*----------------------------------------------------------------------------
  Send an error response back to the client.

-----------------------------------------------------------------------------*/
    ResponseStatus(abyssSessionP, (uint16_t) status);
    ResponseError(abyssSessionP);
}
Exemplo n.º 13
0
static void 
sendResponse(xmlrpc_env *      const envP,
             TSession *        const abyssSessionP, 
             const char *      const body, 
             size_t            const len,
             bool              const chunked,
             ResponseAccessCtl const accessControl) {
/*----------------------------------------------------------------------------
   Generate an HTTP response containing body 'body' of length 'len'
   characters.

   This is meant to run in the context of an Abyss URI handler for
   Abyss session 'abyssSessionP'.
-----------------------------------------------------------------------------*/
    const char * http_cookie = NULL;
        /* This used to set http_cookie to getenv("HTTP_COOKIE"), but
           that doesn't make any sense -- environment variables are not
           appropriate for this.  So for now, cookie code is disabled.
           - Bryan 2004.10.03.
        */

    /* Various bugs before Xmlrpc-c 1.05 caused the response to be not
       chunked in the most basic case, but chunked if the client explicitly
       requested keepalive.  I think it's better not to chunk, because
       it's simpler, so I removed this in 1.05.  I don't know what the
       purpose of chunking would be, and an original comment suggests
       the author wasn't sure chunking was a good idea.

       In 1.06 we added the user option to chunk.
    */
    if (chunked)
        ResponseChunked(abyssSessionP);

    ResponseStatus(abyssSessionP, 200);

    if (http_cookie)
        /* There's an auth cookie, so pass it back in the response. */
        addAuthCookie(envP, abyssSessionP, http_cookie);

    if ((size_t)(uint32_t)len != len)
        xmlrpc_faultf(envP, "XML-RPC method generated a response too "
                      "large for Abyss to send");
    else {
        uint32_t const abyssLen = (uint32_t)len;

        /* See discussion below of quotes around "utf-8" */
        ResponseContentType(abyssSessionP, "text/xml; charset=utf-8");
        ResponseContentLength(abyssSessionP, abyssLen);
        ResponseAccessControl(abyssSessionP, accessControl);
        
        ResponseWriteStart(abyssSessionP);
        ResponseWriteBody(abyssSessionP, body, abyssLen);
        ResponseWriteEnd(abyssSessionP);
    }
}
Exemplo n.º 14
0
Arquivo: main.c Projeto: roguehit/aos3
abyss_bool HandleStatus(TSession *r)
{
    uint32_t status;

    if (sscanf(r->uri,"/status/%d",&status)<=0)
        return FALSE;

    ResponseStatus(r,(uint16_t)status);

    return TRUE;
}
Exemplo n.º 15
0
    static void remoteCommandFailedEarly(
            const ReplicationExecutor::CallbackData& cbData,
            const ReplicationExecutor::RemoteCommandCallbackFn& cb,
            const ReplicationExecutor::RemoteCommandRequest& request) {

        invariant(!cbData.status.isOK());
        cb(ReplicationExecutor::RemoteCommandCallbackData(
                   cbData.executor,
                   cbData.myHandle,
                   request,
                   ResponseStatus(cbData.status)));
    }
Exemplo n.º 16
0
void
RequestRead(TSession * const sessionP,
            uint32_t   const timeout) {
/*----------------------------------------------------------------------------
   Read the headers of a new HTTP request (assuming nothing has yet been
   read on the session).

   Update *sessionP with the information from the headers.

   Leave the connection positioned to the body of the request, ready
   to be read by an HTTP request handler (via SessionRefillBuffer() and
   SessionGetReadData()).
-----------------------------------------------------------------------------*/
    time_t const deadline = time(NULL) + timeout;

    uint16_t httpErrorCode;  /* zero for no error */
    char * requestLine;  /* In connection;s internal buffer */

    readRequestHeader(sessionP, deadline, &requestLine, &httpErrorCode);
    if (!httpErrorCode) {
        TMethod httpMethod;
        const char * host;
        const char * path;
        const char * query;
        unsigned short port;
        bool moreHeaders;

        parseRequestLine(requestLine, &httpMethod, &sessionP->version,
                         &host, &port, &path, &query,
                         &moreHeaders, &httpErrorCode);

        if (!httpErrorCode) {
            initRequestInfo(&sessionP->requestInfo, sessionP->version,
                            requestLine,
                            httpMethod, host, port, path, query);

            if (moreHeaders)
                readAndProcessHeaders(sessionP, deadline, &httpErrorCode);

            if (httpErrorCode == 0)
                sessionP->validRequest = true;

            xmlrpc_strfreenull(host);
            xmlrpc_strfree(path);
            xmlrpc_strfreenull(query);
        }
    }
    if (httpErrorCode)
        ResponseStatus(sessionP, httpErrorCode);
}
Exemplo n.º 17
0
static void
handleReqTooNewHttpVersion(TSession * const sessionP) {

    const char * msg;

    ResponseStatus(sessionP, 505);

    xmlrpc_asprintf(&msg, "Request is in HTTP Version %u"
                    "We understand only HTTP 1",
                    sessionP->version.major);
    
    ResponseError2(sessionP, msg);
    
    xmlrpc_strfree(msg);
}
Exemplo n.º 18
0
    ResponseStatus NetworkInterfaceMock::runCommand(
            const ReplicationExecutor::RemoteCommandRequest& request) {
        boost::unique_lock<boost::mutex> lk(_mutex);
        Date_t wakeupTime = _now + _simulatedNetworkLatencyMillis;
        while (wakeupTime < _now) {
            _timeElapsed.wait(lk);
        }

        StatusWith<int> toStatus = getTimeoutMillis(request.expirationDate, _now);
        if (!toStatus.isOK())
            return ResponseStatus(toStatus.getStatus());

        lk.unlock();
        return _helper(request);
    }
Exemplo n.º 19
0
    static void remoteCommandFinished(
            const ReplicationExecutor::CallbackData& cbData,
            const ReplicationExecutor::RemoteCommandCallbackFn& cb,
            const ReplicationExecutor::RemoteCommandRequest& request,
            const ResponseStatus& response) {

        if (cbData.status.isOK()) {
            cb(ReplicationExecutor::RemoteCommandCallbackData(
                       cbData.executor, cbData.myHandle, request, response));
        }
        else {
            cb(ReplicationExecutor::RemoteCommandCallbackData(
                       cbData.executor,
                       cbData.myHandle,
                       request,
                       ResponseStatus(cbData.status)));
        }
    }
Exemplo n.º 20
0
Arquivo: main.c Projeto: roguehit/aos3
void Answer(TSession *r, uint16_t statuscode, char *buffer)
{
    ResponseChunked(r);

    ResponseStatus(r,statuscode);

    ResponseContentType(r,"text/html");

    ResponseWriteStart(r);
    
    HTTPWrite(r,"<HTML><BODY>",12);
    
    HTTPWrite(r,buffer,strlen(buffer));

    HTTPWrite(r,"</BODY></HTML>",14);

    HTTPWriteEnd(r);
}
Exemplo n.º 21
0
 ResponseStatus NetworkInterfaceMockWithMap::_getResponseFromMap(
                             const ReplicationExecutor::RemoteCommandRequest& request) {
     boost::unique_lock<boost::mutex> lk(_mutex);
     while (1) {
         BlockableResponseStatus result = mapFindWithDefault(
                                     _responses,
                                     request,
                                     BlockableResponseStatus(
                                         ResponseStatus(
                                              ErrorCodes::NoSuchKey,
                                              str::stream() << "Could not find response for " <<
                                              "Request(" << request.target.toString() << ", " <<
                                              request.dbname << ", " << request.cmdObj << ')'),
                                         false));
         if (!result.isBlocked) {
             return result.response;
         }
         _someResponseUnblocked.wait(lk);
     }
 }
Exemplo n.º 22
0
/**************************************
* SendResponse
*	Envia la respuesta de una peticion
**************************************/
int XmlRpcServer::SendResponse(TSession *r, short code, const char *msg, int length)
{
	//Chunked output
	ResponseChunked(r);

	//POnemos el codigo
	ResponseStatus(r,code);

	//El content length
	ResponseContentLength(r, length);

	//Escribimos la respuesta
	ResponseWriteStart(r);
	
	//La mandamos
	ResponseWriteBody(r,(char*)msg,length);

	//End it
	ResponseWriteEnd(r);

	return 1;
}
Exemplo n.º 23
0
static void
processRequestFromClient(TConn *  const connectionP,
                         bool     const lastReqOnConn,
                         uint32_t const timeout,
                         bool *   const keepAliveP) {
/*----------------------------------------------------------------------------
   Get and execute one HTTP request from client connection *connectionP,
   through the connection buffer.  I.e. Some of the request may already be in
   the connection buffer, and we may leave some of later requests in the
   connection buffer.

   In fact, due to timing considerations, we assume the client has begun
   sending the request, which as a practical matter means Caller has already
   deposited some of it in the connection buffer.

   If there isn't one full request in the buffer now, we wait for one full
   request to come through the buffer, up to 'timeout'.

   We return as *keepAliveP whether Caller should keep the connection
   alive for a while for possible future requests from the client, based
   on 'lastReqOnConn' and the content of the HTTP request.

   Executing the request consists primarily of calling the URI handlers that
   are associated with the connection (*connectionP), passing each the request
   information we read.  Each handler can respond according to the HTTP method
   (GET, POST, etc) and URL etc, and that response may be either to
   execute the request and send the response or refuse the request and let
   us call the next one in the list.
-----------------------------------------------------------------------------*/
    TSession session;
    const char * error;
    uint16_t httpErrorCode;

    RequestInit(&session, connectionP);

    session.serverDeniesKeepalive = lastReqOnConn;
        
    RequestRead(&session, timeout, &error, &httpErrorCode);

    if (error) {
        ResponseStatus(&session, httpErrorCode);
        ResponseError2(&session, error);
        xmlrpc_strfree(error);
    } else {
        if (session.version.major >= 2)
            handleReqTooNewHttpVersion(&session);
        else if (!RequestValidURI(&session))
            handleReqInvalidURI(&session);
        else
            runUserHandler(&session, connectionP->server->srvP);
    }

    assert(session.status != 0);

    if (session.responseStarted)
        HTTPWriteEndChunk(&session);
    else
        ResponseError(&session);

    *keepAliveP = HTTPKeepalive(&session);

    SessionLog(&session);

    RequestFree(&session);
}
Exemplo n.º 24
0
static abyss_bool
ServerDefaultHandlerFunc(TSession * const sessionP) {

    struct _TServer * const srvP = ConnServer(sessionP->conn)->srvP;

    char *p;
    char z[4096];
    TFileStat fs;
    unsigned int i;
    abyss_bool endingslash=FALSE;

    if (!RequestValidURIPath(sessionP)) {
        ResponseStatus(sessionP, 400);
        return TRUE;
    }

    /* Must check for * (asterisk uri) in the future */
    if (sessionP->request_info.method == m_options) {
        ResponseAddField(sessionP, "Allow", "GET, HEAD");
        ResponseContentLength(sessionP, 0);
        ResponseStatus(sessionP, 200);
        return TRUE;
    }

    if ((sessionP->request_info.method != m_get) &&
        (sessionP->request_info.method != m_head)) {
        ResponseAddField(sessionP, "Allow", "GET, HEAD");
        ResponseStatus(sessionP, 405);
        return TRUE;
    }

    strcpy(z, srvP->filespath);
    strcat(z, sessionP->request_info.uri);

    p = z + strlen(z) - 1;
    if (*p == '/') {
        endingslash = TRUE;
        *p = '\0';
    }

#ifdef WIN32
    p = z;
    while (*p) {
        if ((*p) == '/')
            *p= '\\';

        ++p;
    }
#endif  /* WIN32 */

    if (!FileStat(z, &fs)) {
        ResponseStatusErrno(sessionP);
        return TRUE;
    }

    if (fs.st_mode & S_IFDIR) {
        /* Redirect to the same directory but with the ending slash
        ** to avoid problems with some browsers (IE for examples) when
        ** they generate relative urls */
        if (!endingslash) {
            strcpy(z, sessionP->request_info.uri);
            p = z+strlen(z);
            *p = '/';
            *(p+1) = '\0';
            ResponseAddField(sessionP, "Location", z);
            ResponseStatus(sessionP, 302);
            ResponseWrite(sessionP);
            return TRUE;
        }

        *p = DIRECTORY_SEPARATOR[0];
        ++p;

        i = srvP->defaultfilenames.size;
        while (i-- > 0) {
            *p = '\0';        
            strcat(z, (srvP->defaultfilenames.item[i]));
            if (FileStat(z, &fs)) {
                if (!(fs.st_mode & S_IFDIR))
                    return ServerFileHandler(sessionP, z, fs.st_mtime,
                                             srvP->mimeTypeP);
            }
        }

        *(p-1) = '\0';
        
        if (!FileStat(z, &fs)) {
            ResponseStatusErrno(sessionP);
            return TRUE;
        }
        return ServerDirectoryHandler(sessionP, z, fs.st_mtime,
                                      srvP->mimeTypeP);
    } else
        return ServerFileHandler(sessionP, z, fs.st_mtime,
                                 srvP->mimeTypeP);
}
Exemplo n.º 25
0
static abyss_bool
ServerFileHandler(TSession * const r,
                  char *     const z,
                  time_t     const fileModTime,
                  MIMEType * const mimeTypeP) {

    const char * mediatype;
    TFile file;
    uint64_t filesize;
    uint64_t start;
    uint64_t end;
    TDate date;
    char * p;
    TDate filedate;
    
    mediatype = MIMETypeGuessFromFile2(mimeTypeP, z);

    if (!FileOpen(&file,z,O_BINARY | O_RDONLY)) {
        ResponseStatusErrno(r);
        return TRUE;
    }

    fileDate(r, fileModTime, &filedate);

    p = RequestHeaderValue(r, "if-modified-since");
    if (p) {
        if (DateDecode(p,&date)) {
            if (DateCompare(&filedate, &date) <= 0) {
                ResponseStatus(r, 304);
                ResponseWrite(r);
                return TRUE;
            } else
                r->ranges.size = 0;
        }
    }
    filesize = FileSize(&file);

    switch (r->ranges.size) {
    case 0:
        ResponseStatus(r, 200);
        break;

    case 1: {
        abyss_bool decoded;
        decoded = RangeDecode((char *)(r->ranges.item[0]), filesize,
                              &start, &end);
        if (!decoded) {
            ListFree(&(r->ranges));
            ResponseStatus(r, 200);
            break;
        }
        
        sprintf(z, "bytes %llu-%llu/%llu", start, end, filesize);

        ResponseAddField(r, "Content-range", z);
        ResponseContentLength(r, end - start + 1);
        ResponseStatus(r, 206);
    } break;

    default:
        ResponseContentType(r, "multipart/ranges; boundary=" BOUNDARY);
        ResponseStatus(r, 206);
        break;
    }
    
    if (r->ranges.size == 0) {
        ResponseContentLength(r, filesize);
        ResponseContentType(r, mediatype);
    }
    
    if (DateToString(&filedate, z))
        ResponseAddField(r, "Last-Modified", z);

    ResponseWrite(r);

    if (r->request_info.method != m_head)
        sendBody(r, &file, filesize, mediatype, start, end, z);

    FileClose(&file);

    return TRUE;
}
Exemplo n.º 26
0
static abyss_bool
ServerDirectoryHandler(TSession * const r,
                       char *     const z,
                       time_t     const fileModTime,
                       MIMEType * const mimeTypeP) {

    TList list;
    abyss_bool text;
    abyss_bool ascending;
    uint16_t sort;    /* 1=by name, 2=by date */
    TPool pool;
    TDate date;
    const char * error;
    uint16_t responseStatus;
    TDate dirdate;
    const char * imsHdr;
    
    determineSortType(r->request_info.query, &ascending, &sort, &text, &error);

    if (error) {
        ResponseStatus(r,400);
        xmlrpc_strfree(error);
        return TRUE;
    }

    fileDate(r, fileModTime, &dirdate);

    imsHdr = RequestHeaderValue(r, "If-Modified-Since");
    if (imsHdr) {
        if (DateDecode(imsHdr, &date)) {
            if (DateCompare(&dirdate, &date) <= 0) {
                ResponseStatus(r, 304);
                ResponseWrite(r);
                return TRUE;
            }
        }
    }

    if (!PoolCreate(&pool, 1024)) {
        ResponseStatus(r, 500);
        return TRUE;
    }

    generateListing(&list, z, r->request_info.uri,
                    &pool, &error, &responseStatus);
    if (error) {
        ResponseStatus(r, responseStatus);
        xmlrpc_strfree(error);
        PoolFree(&pool);
        return TRUE;
    }

    /* Send something to the user to show that we are still alive */
    ResponseStatus(r, 200);
    ResponseContentType(r, (text ? "text/plain" : "text/html"));

    if (DateToString(&dirdate, z))
        ResponseAddField(r, "Last-Modified", z);
    
    ResponseChunked(r);
    ResponseWrite(r);

    if (r->request_info.method!=m_head)
        sendDirectoryDocument(&list, ascending, sort, text,
                              r->request_info.uri, mimeTypeP, r, z);

    HTTPWriteEndChunk(r);

    /* Free memory and exit */
    ListFree(&list);
    PoolFree(&pool);

    return TRUE;
}
Exemplo n.º 27
0
Status NetworkInterfaceASIO::startCommand(const TaskExecutor::CallbackHandle& cbHandle,
                                          RemoteCommandRequest& request,
                                          const RemoteCommandCompletionFn& onFinish) {
    MONGO_ASIO_INVARIANT(onFinish, "Invalid completion function");
    {
        stdx::lock_guard<stdx::mutex> lk(_inProgressMutex);
        const auto insertResult = _inGetConnection.emplace(cbHandle);
        // We should never see the same CallbackHandle added twice
        MONGO_ASIO_INVARIANT_INLOCK(insertResult.second, "Same CallbackHandle added twice");
    }

    if (inShutdown()) {
        return {ErrorCodes::ShutdownInProgress, "NetworkInterfaceASIO shutdown in progress"};
    }

    LOG(2) << "startCommand: " << redact(request.toString());

    auto getConnectionStartTime = now();

    auto statusMetadata = attachMetadataIfNeeded(request, _metadataHook.get());
    if (!statusMetadata.isOK()) {
        return statusMetadata;
    }

    auto nextStep = [this, getConnectionStartTime, cbHandle, request, onFinish](
        StatusWith<ConnectionPool::ConnectionHandle> swConn) {

        if (!swConn.isOK()) {
            LOG(2) << "Failed to get connection from pool for request " << request.id << ": "
                   << swConn.getStatus();

            bool wasPreviouslyCanceled = false;
            {
                stdx::lock_guard<stdx::mutex> lk(_inProgressMutex);
                wasPreviouslyCanceled = _inGetConnection.erase(cbHandle) == 0;
            }

            Status status = wasPreviouslyCanceled
                ? Status(ErrorCodes::CallbackCanceled, "Callback canceled")
                : swConn.getStatus();
            if (status.code() == ErrorCodes::NetworkInterfaceExceededTimeLimit) {
                status = Status(ErrorCodes::ExceededTimeLimit, status.reason());
            }
            if (status.code() == ErrorCodes::ExceededTimeLimit) {
                _numTimedOutOps.fetchAndAdd(1);
            }
            if (status.code() != ErrorCodes::CallbackCanceled) {
                _numFailedOps.fetchAndAdd(1);
            }

            onFinish({status, now() - getConnectionStartTime});
            signalWorkAvailable();
            return;
        }

        auto conn = static_cast<connection_pool_asio::ASIOConnection*>(swConn.getValue().get());

        AsyncOp* op = nullptr;

        stdx::unique_lock<stdx::mutex> lk(_inProgressMutex);

        const auto eraseCount = _inGetConnection.erase(cbHandle);

        // If we didn't find the request, we've been canceled
        if (eraseCount == 0) {
            lk.unlock();

            onFinish({ErrorCodes::CallbackCanceled,
                      "Callback canceled",
                      now() - getConnectionStartTime});

            // Though we were canceled, we know that the stream is fine, so indicate success.
            conn->indicateSuccess();

            signalWorkAvailable();

            return;
        }

        // We can't release the AsyncOp until we know we were not canceled.
        auto ownedOp = conn->releaseAsyncOp();
        op = ownedOp.get();

        // This AsyncOp may be recycled. We expect timeout and canceled to be clean.
        // If this op was most recently used to connect, its state transitions won't have been
        // reset, so we do that here.
        MONGO_ASIO_INVARIANT_INLOCK(!op->canceled(), "AsyncOp has dirty canceled flag", op);
        MONGO_ASIO_INVARIANT_INLOCK(!op->timedOut(), "AsyncOp has dirty timeout flag", op);
        op->clearStateTransitions();

        // Now that we're inProgress, an external cancel can touch our op, but
        // not until we release the inProgressMutex.
        _inProgress.emplace(op, std::move(ownedOp));

        op->_cbHandle = std::move(cbHandle);
        op->_request = std::move(request);
        op->_onFinish = std::move(onFinish);
        op->_connectionPoolHandle = std::move(swConn.getValue());
        op->startProgress(getConnectionStartTime);

        // This ditches the lock and gets us onto the strand (so we're
        // threadsafe)
        op->_strand.post([this, op, getConnectionStartTime] {
            const auto timeout = op->_request.timeout;

            // Set timeout now that we have the correct request object
            if (timeout != RemoteCommandRequest::kNoTimeout) {
                // Subtract the time it took to get the connection from the pool from the request
                // timeout.
                auto getConnectionDuration = now() - getConnectionStartTime;
                if (getConnectionDuration >= timeout) {
                    // We only assume that the request timer is guaranteed to fire *after* the
                    // timeout duration - but make no stronger assumption. It is thus possible that
                    // we have already exceeded the timeout. In this case we timeout the operation
                    // manually.
                    std::stringstream msg;
                    msg << "Remote command timed out while waiting to get a connection from the "
                        << "pool, took " << getConnectionDuration << ", timeout was set to "
                        << timeout;
                    auto rs = ResponseStatus(ErrorCodes::NetworkInterfaceExceededTimeLimit,
                                             msg.str(),
                                             getConnectionDuration);
                    return _completeOperation(op, rs);
                }

                // The above conditional guarantees that the adjusted timeout will never underflow.
                MONGO_ASIO_INVARIANT(timeout > getConnectionDuration, "timeout underflowed", op);
                const auto adjustedTimeout = timeout - getConnectionDuration;
                const auto requestId = op->_request.id;

                try {
                    op->_timeoutAlarm =
                        op->_owner->_timerFactory->make(&op->_strand, adjustedTimeout);
                } catch (std::system_error& e) {
                    severe() << "Failed to construct timer for AsyncOp: " << e.what();
                    fassertFailed(40334);
                }

                std::shared_ptr<AsyncOp::AccessControl> access;
                std::size_t generation;
                {
                    stdx::lock_guard<stdx::mutex> lk(op->_access->mutex);
                    access = op->_access;
                    generation = access->id;
                }

                op->_timeoutAlarm->asyncWait(
                    [this, op, access, generation, requestId, adjustedTimeout](std::error_code ec) {
                        // We must pass a check for safe access before using op inside the
                        // callback or we may attempt access on an invalid pointer.
                        stdx::lock_guard<stdx::mutex> lk(access->mutex);
                        if (generation != access->id) {
                            // The operation has been cleaned up, do not access.
                            return;
                        }

                        if (!ec) {
                            LOG(2) << "Request " << requestId << " timed out"
                                   << ", adjusted timeout after getting connection from pool was "
                                   << adjustedTimeout << ", op was " << redact(op->toString());

                            op->timeOut_inlock();
                        } else {
                            LOG(2) << "Failed to time request " << requestId
                                   << "out: " << ec.message() << ", op was "
                                   << redact(op->toString());
                        }
                    });
            }

            _beginCommunication(op);
        });
    };

    _connectionPool.get(request.target, request.timeout, nextStep);
    return Status::OK();
}
Exemplo n.º 28
0
abyss_bool
RequestAuth(TSession *   const sessionP,
            const char * const credential,
            const char * const user,
            const char * const pass) {
/*----------------------------------------------------------------------------
   Authenticate requester, in a very simplistic fashion.

   If the request executing on session *sessionP specifies basic
   authentication (via Authorization header) with username 'user', password
   'pass', then return true.  Else, return false and set up an authorization
   failure response (HTTP response status 401) that says user must supply an
   identity in the 'credential' domain.

   When we return true, we also set the username in the request info for the
   session to 'user' so that a future SessionGetRequestInfo can get it.
-----------------------------------------------------------------------------*/
    bool authorized;
    const char * authValue;

    authValue = RequestHeaderValue(sessionP, "authorization");
    if (authValue) {
        char * const valueBuffer = malloc(strlen(authValue));
            /* A buffer we can mangle as we parse the authorization: value */

        if (!authValue)
            /* Should return error, but we have no way to do that */
            authorized = false;
        else {
            const char * authType;
            char * authHdrPtr;

            strcpy(valueBuffer, authValue);
            authHdrPtr = &valueBuffer[0];

            NextToken((const char **)&authHdrPtr);
            GetTokenConst(&authHdrPtr, &authType);
            if (authType) {
                if (xmlrpc_strcaseeq(authType, "basic")) {
                    const char * userPass;
                    char userPassEncoded[80];

                    NextToken((const char **)&authHdrPtr);

                    xmlrpc_asprintf(&userPass, "%s:%s", user, pass);
                    xmlrpc_base64Encode(userPass, userPassEncoded);
                    xmlrpc_strfree(userPass);

                    if (xmlrpc_streq(authHdrPtr, userPassEncoded)) {
                        sessionP->requestInfo.user = xmlrpc_strdupsol(user);
                        authorized = true;
                    } else
                        authorized = false;
                } else
                    authorized = false;
            } else
                authorized = false;

            free(valueBuffer);
        }
    } else
        authorized = false;

    if (!authorized) {
        const char * hdrValue;
        xmlrpc_asprintf(&hdrValue, "Basic realm=\"%s\"", credential);
        ResponseAddField(sessionP, "WWW-Authenticate", hdrValue);

        xmlrpc_strfree(hdrValue);

        ResponseStatus(sessionP, 401);
    }
    return authorized;
}
Exemplo n.º 29
0
abyss_bool
RequestRead(TSession * const sessionP) {
    uint16_t httpErrorCode;  /* zero for no error */
    char * requestLine;

    readRequestLine(sessionP, &requestLine, &httpErrorCode);
    if (!httpErrorCode) {
        TMethod httpMethod;
        const char * host;
        const char * path;
        const char * query;
        unsigned short port;
        abyss_bool moreHeaders=false;

        parseRequestLine(requestLine, &httpMethod, &sessionP->version,
                         &host, &port, &path, &query,
                         &moreHeaders, &httpErrorCode);

        if (!httpErrorCode)
            initRequestInfo(&sessionP->request_info, sessionP->version,
                            strdup(requestLine),
                            httpMethod, host, port, path, query);

        while (moreHeaders && !httpErrorCode) {
            char * p;
            abyss_bool succeeded;
            succeeded = ConnReadHeader(sessionP->conn, &p);
            if (!succeeded)
                httpErrorCode = 408;  /* Request Timeout */
            else {
                if (!*p)
                    /* We have reached the empty line so all the request
                       was read.
                    */
                    moreHeaders = FALSE;
                else {
                    char * fieldName;
                    getFieldNameToken(&p, &fieldName, &httpErrorCode);
                    if (!httpErrorCode) {
                        char * fieldValue;

                        NextToken((const char **)&p);
                        
                        fieldValue = p;
                        
                        TableAdd(&sessionP->request_headers,
                                 fieldName, fieldValue);
                        
                        processHeader(fieldName, fieldValue, sessionP,
                                      &httpErrorCode);
                    }
                }
            }
        }
    }
    if (httpErrorCode)
        ResponseStatus(sessionP, httpErrorCode);
    else
        sessionP->validRequest = true;

    return !httpErrorCode;
}
Exemplo n.º 30
0
void
ResponseStatusErrno(TSession * const sessionP) {

    ResponseStatus(sessionP, ResponseStatusFromErrno(errno));
}