Exemple #1
0
static void OnData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) {
    switch (type) {
        case kCFSocketDataCallBack:
            CFDataRef data(reinterpret_cast<CFDataRef>(value));
            Client *client(reinterpret_cast<Client *>(info));

            if (client->message_ == NULL)
                client->message_ = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE);

            if (!CFHTTPMessageAppendBytes(client->message_, CFDataGetBytePtr(data), CFDataGetLength(data)))
                CFLog(kCFLogLevelError, CFSTR("CFHTTPMessageAppendBytes()"));
            else if (CFHTTPMessageIsHeaderComplete(client->message_)) {
                CFURLRef url(CFHTTPMessageCopyRequestURL(client->message_));
                Boolean absolute;
                CFStringRef path(CFURLCopyStrictPath(url, &absolute));
                CFRelease(client->message_);

                CFStringRef code(CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, path, CFSTR("")));
                CFRelease(path);

                JSStringRef script(JSStringCreateWithCFString(code));
                CFRelease(code);

                JSValueRef result(JSEvaluateScript(CYGetJSContext(), script, NULL, NULL, 0, NULL));
                JSStringRelease(script);

                CFHTTPMessageRef response(CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1));
                CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Type"), CFSTR("application/json; charset=utf-8"));

                CFStringRef json(CYCopyJSONString(CYGetJSContext(), result, NULL));
                CFDataRef body(CFStringCreateExternalRepresentation(kCFAllocatorDefault, json, kCFStringEncodingUTF8, NULL));
                CFRelease(json);

                CFStringRef length(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), CFDataGetLength(body)));
                CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Length"), length);
                CFRelease(length);

                CFHTTPMessageSetBody(response, body);
                CFRelease(body);

                CFDataRef serialized(CFHTTPMessageCopySerializedMessage(response));
                CFRelease(response);

                CFSocketSendData(socket, NULL, serialized, 0);
                CFRelease(serialized);

                CFRelease(url);
            }
        break;
    }
}
static void do_upload__string(
    SG_context* pCtx,
    const char* pszUrl,
    const char* psz_method,
    SG_pathname* pPath,
    const char* psz_username,
    const char* psz_password,
    SG_string** ppstr
)
{
    SG_string* pstr = NULL;
    CFHTTPMessageRef myRequest = NULL;
    CFHTTPMessageRef myResponse = NULL;
    CFStringRef s_username = NULL;
    CFStringRef s_password = NULL;

    SG_ERR_CHECK(  make_request(pCtx, pszUrl, psz_method, NULL, &myRequest)  );
    SG_ERR_CHECK(  perform_upload_request__string(pCtx, myRequest, pPath, &myResponse, &pstr)  );
#if 0
    {
        CFDataRef d = CFHTTPMessageCopySerializedMessage(myResponse);
        fprintf(stderr, "%s\n", CFDataGetBytePtr(d));
        CFRelease(d);
    }
#endif
    UInt32 statusCode = CFHTTPMessageGetResponseStatusCode(myResponse);

    if (
        psz_username
        && psz_password
        && (statusCode == 401 || statusCode == 407)
    )
    {
        s_username = CFStringCreateWithCString(kCFAllocatorDefault, psz_username, kCFStringEncodingUTF8);
        s_password = CFStringCreateWithCString(kCFAllocatorDefault, psz_password, kCFStringEncodingUTF8);
        if (!CFHTTPMessageAddAuthentication(myRequest, myResponse, s_username, s_password, kCFHTTPAuthenticationSchemeDigest, FALSE))
        {
            SG_ERR_THROW2(SG_ERR_UNSPECIFIED, (pCtx, "CFHTTPMessageAddAuthentication failed"));
        }

#if 0
        {
            CFDataRef d = CFHTTPMessageCopySerializedMessage(myRequest);
            fprintf(stderr, "%s\n", CFDataGetBytePtr(d));
            CFRelease(d);
        }
#endif

        CFRelease(s_username);
        s_username = NULL;

        CFRelease(s_password);
        s_password = NULL;

        CFRelease(myResponse);
        myResponse = NULL;

        SG_STRING_NULLFREE(pCtx, pstr);
        SG_ERR_CHECK(  perform_upload_request__string(pCtx, myRequest, pPath, &myResponse, &pstr)  );

#if 0
        {
            CFDataRef d = CFHTTPMessageCopySerializedMessage(myResponse);
            fprintf(stderr, "%s\n", CFDataGetBytePtr(d));
            CFRelease(d);
        }
#endif
        statusCode = CFHTTPMessageGetResponseStatusCode(myResponse);
    }

    if (statusCode != 200)
    {
        SG_ERR_THROW2_RETURN(SG_ERR_SERVER_HTTP_ERROR, (pCtx, "%d", (int) statusCode));
    }

    *ppstr = pstr;
    pstr = NULL;

    /* fall through */

fail:
    if (s_username)
    {
        CFRelease(s_username);
        s_username = NULL;
    }
    if (s_password)
    {
        CFRelease(s_password);
        s_password = NULL;
    }
    if (myRequest)
    {
        CFRelease(myRequest);
        myRequest = NULL;
    }

    if (myResponse)
    {
        CFRelease(myResponse);
        myResponse = NULL;
    }

    SG_STRING_NULLFREE(pCtx, pstr);
}
// TODO give this a better name.  It gets used outside this file now.
void do_url(
    SG_context* pCtx,
    const char* pszUrl,
    const char* psz_method,
    const char* psz_data,
    const char* psz_username,
    const char* psz_password,
    SG_string** ppstr,
    SG_pathname* pPath,
    SG_bool b_progress
)
{
    SG_string* pstr = NULL;
    CFHTTPMessageRef myRequest = NULL;
    CFHTTPMessageRef myResponse = NULL;
    CFStringRef s_username = NULL;
    CFStringRef s_password = NULL;

    if (pPath && ppstr)
    {
        SG_ERR_RESET_THROW2(SG_ERR_INVALIDARG, (pCtx, "do_url() returns into a string or a file, but not both"));
    }

    if (!pPath && !ppstr)
    {
        SG_ERR_RESET_THROW2(SG_ERR_INVALIDARG, (pCtx, "do_url() returns into a string or a file, one or the other"));
    }

    SG_ERR_CHECK(  make_request(pCtx, pszUrl, psz_method, psz_data, &myRequest)  );

#if 0
    {
        CFDataRef d = CFHTTPMessageCopySerializedMessage(myRequest);
        fprintf(stderr, "%s\n", CFDataGetBytePtr(d));
        CFRelease(d);
    }
#endif

    if (pPath)
    {
        SG_ERR_CHECK(  perform_request__file(pCtx, myRequest, &myResponse, pPath, b_progress)  );
    }
    else
    {
        SG_ERR_CHECK(  perform_request__string(pCtx, myRequest, &myResponse, &pstr)  );
    }

    if (!myResponse)
    {
        SG_ERR_THROW2(SG_ERR_UNSPECIFIED, (pCtx, "No response from server"));
    }

    //fprintf(stderr, "\n%s\n", SG_string__sz(pstr));
    UInt32 statusCode = CFHTTPMessageGetResponseStatusCode(myResponse);
#if 0
    {
        CFDataRef d = CFHTTPMessageCopySerializedMessage(myResponse);
        fprintf(stderr, "%s\n", CFDataGetBytePtr(d));
        CFRelease(d);
    }
#endif

    if (
        psz_username
        && psz_password
        && (statusCode == 401 || statusCode == 407)
    )
    {
        s_username = CFStringCreateWithCString(kCFAllocatorDefault, psz_username, kCFStringEncodingUTF8);
        s_password = CFStringCreateWithCString(kCFAllocatorDefault, psz_password, kCFStringEncodingUTF8);
        if (!CFHTTPMessageAddAuthentication(myRequest, myResponse, s_username, s_password, kCFHTTPAuthenticationSchemeDigest, FALSE))
        {
            SG_ERR_THROW2(SG_ERR_UNSPECIFIED, (pCtx, "CFHTTPMessageAddAuthentication failed"));
        }

#if 0
        {
            CFDataRef d = CFHTTPMessageCopySerializedMessage(myRequest);
            fprintf(stderr, "%s\n", CFDataGetBytePtr(d));
            CFRelease(d);
        }
#endif

        CFRelease(s_username);
        s_username = NULL;

        CFRelease(s_password);
        s_password = NULL;

        CFRelease(myResponse);
        myResponse = NULL;

        if (pPath)
        {
            SG_ERR_IGNORE(  SG_fsobj__remove__pathname(pCtx, pPath)  );
            SG_ERR_CHECK(  perform_request__file(pCtx, myRequest, &myResponse, pPath, b_progress)  );
        }
        else
        {
            SG_STRING_NULLFREE(pCtx, pstr);
            SG_ERR_CHECK(  perform_request__string(pCtx, myRequest, &myResponse, &pstr)  );
        }
#if 0
        {
            CFDataRef d = CFHTTPMessageCopySerializedMessage(myResponse);
            fprintf(stderr, "%s\n", CFDataGetBytePtr(d));
            CFRelease(d);
        }
#endif
        statusCode = CFHTTPMessageGetResponseStatusCode(myResponse);
    }

    if (statusCode != 200)
    {
        if (401 == statusCode)
        {
            SG_ERR_THROW(SG_ERR_HTTP_401);
        }
        else if (404 == statusCode)
        {
            SG_ERR_THROW(SG_ERR_HTTP_404);
        }
        else if (502 == statusCode)
        {
            SG_ERR_THROW(SG_ERR_HTTP_502);
        }
        else
        {
            SG_ERR_THROW2(SG_ERR_SERVER_HTTP_ERROR, (pCtx, "%d", (int) statusCode));
        }
    }

    if (ppstr)
    {
        *ppstr = pstr;
        pstr = NULL;
    }

    /* fall through */

fail:
    if (s_username)
    {
        CFRelease(s_username);
        s_username = NULL;
    }

    if (s_password)
    {
        CFRelease(s_password);
        s_password = NULL;
    }

    if (myRequest)
    {
        CFRelease(myRequest);
        myRequest = NULL;
    }

    if (myResponse)
    {
        CFRelease(myResponse);
        myResponse = NULL;
    }

    SG_STRING_NULLFREE(pCtx, pstr);
}