Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 899ed754 authored by Andreas Huber's avatar Andreas Huber Committed by Android Git Automerger
Browse files

am 30c81844: Merge "DO NOT MERGE Support for "chunked" HTTP transfer encoding." into gingerbread

* commit '30c818444d876dd868b84adec2416308c90f32e3':
  DO NOT MERGE Support for "chunked" HTTP transfer encoding.
parents 8e37a5c7 03b55cc9
Loading
Loading
Loading
Loading
+102 −2
Original line number Diff line number Diff line
@@ -67,7 +67,9 @@ NuHTTPDataSource::NuHTTPDataSource()
      mPort(0),
      mOffset(0),
      mContentLength(0),
      mContentLengthValid(false) {
      mContentLengthValid(false),
      mHasChunkedTransferEncoding(false),
      mChunkDataBytesLeft(0) {
}

NuHTTPDataSource::~NuHTTPDataSource() {
@@ -184,6 +186,30 @@ status_t NuHTTPDataSource::connect(
            return ERROR_IO;
        }

        mHasChunkedTransferEncoding = false;

        {
            string value;
            if (mHTTP.find_header_value("Transfer-Encoding", &value)
                    || mHTTP.find_header_value("Transfer-encoding", &value)) {
                // We don't currently support any transfer encodings but
                // chunked.

                if (!strcasecmp(value.c_str(), "chunked")) {
                    LOGI("Chunked transfer encoding applied.");
                    mHasChunkedTransferEncoding = true;
                    mChunkDataBytesLeft = 0;
                } else {
                    mState = DISCONNECTED;
                    mHTTP.disconnect();

                    LOGE("We don't support '%s' transfer encoding.", value.c_str());

                    return ERROR_UNSUPPORTED;
                }
            }
        }

        applyTimeoutResponse();

        if (offset == 0) {
@@ -193,8 +219,17 @@ status_t NuHTTPDataSource::connect(
                    && ParseSingleUnsignedLong(value.c_str(), &x)) {
                mContentLength = (off_t)x;
                mContentLengthValid = true;
            } else {
                LOGW("Server did not give us the content length!");
            }
        } else {
            if (httpStatus != 206 /* Partial Content */) {
                // We requested a range but the server didn't support that.
                LOGE("We requested a range but the server didn't "
                     "support that.");
                return ERROR_UNSUPPORTED;
            }

            string value;
            unsigned long x;
            if (mHTTP.find_header_value(string("Content-Range"), &value)) {
@@ -222,6 +257,71 @@ status_t NuHTTPDataSource::initCheck() const {
    return mState == CONNECTED ? OK : NO_INIT;
}

ssize_t NuHTTPDataSource::internalRead(void *data, size_t size) {
    if (!mHasChunkedTransferEncoding) {
        return mHTTP.receive(data, size);
    }

    if (mChunkDataBytesLeft < 0) {
        return 0;
    } else if (mChunkDataBytesLeft == 0) {
        char line[1024];
        status_t err = mHTTP.receive_line(line, sizeof(line));

        if (err != OK) {
            return err;
        }

        LOGV("line = '%s'", line);

        char *end;
        unsigned long n = strtoul(line, &end, 16);

        if (end == line || (*end != ';' && *end != '\0')) {
            LOGE("malformed HTTP chunk '%s'", line);
            return ERROR_MALFORMED;
        }

        mChunkDataBytesLeft = n;
        LOGV("chunk data size = %lu", n);

        if (mChunkDataBytesLeft == 0) {
            mChunkDataBytesLeft = -1;
            return 0;
        }

        // fall through
    }

    if (size > (size_t)mChunkDataBytesLeft) {
        size = mChunkDataBytesLeft;
    }

    ssize_t n = mHTTP.receive(data, size);

    if (n < 0) {
        return n;
    }

    mChunkDataBytesLeft -= (size_t)n;

    if (mChunkDataBytesLeft == 0) {
        char line[1024];
        status_t err = mHTTP.receive_line(line, sizeof(line));

        if (err != OK) {
            return err;
        }

        if (line[0] != '\0') {
            LOGE("missing HTTP chunk terminator.");
            return ERROR_MALFORMED;
        }
    }

    return n;
}

ssize_t NuHTTPDataSource::readAt(off_t offset, void *data, size_t size) {
    LOGV("readAt offset %ld, size %d", offset, size);

@@ -250,7 +350,7 @@ ssize_t NuHTTPDataSource::readAt(off_t offset, void *data, size_t size) {
    size_t numBytesRead = 0;
    while (numBytesRead < size) {
        ssize_t n =
            mHTTP.receive((uint8_t *)data + numBytesRead, size - numBytesRead);
            internalRead((uint8_t *)data + numBytesRead, size - numBytesRead);

        if (n < 0) {
            return n;
+28 −7
Original line number Diff line number Diff line
@@ -318,20 +318,41 @@ status_t LiveSource::fetchM3U(const char *url, sp<ABuffer> *out) {
    status_t err = source->getSize(&size);

    if (err != OK) {
        return err;
        size = 65536;
    }

    sp<ABuffer> buffer = new ABuffer(size);
    size_t offset = 0;
    while (offset < (size_t)size) {
    buffer->setRange(0, 0);

    for (;;) {
        size_t bufferRemaining = buffer->capacity() - buffer->size();

        if (bufferRemaining == 0) {
            bufferRemaining = 32768;

            LOGV("increasing download buffer to %d bytes",
                 buffer->size() + bufferRemaining);

            sp<ABuffer> copy = new ABuffer(buffer->size() + bufferRemaining);
            memcpy(copy->data(), buffer->data(), buffer->size());
            copy->setRange(0, buffer->size());

            buffer = copy;
        }

        ssize_t n = source->readAt(
                offset, buffer->data() + offset, size - offset);
                buffer->size(), buffer->data() + buffer->size(),
                bufferRemaining);

        if (n <= 0) {
            return ERROR_IO;
        if (n < 0) {
            return err;
        }

        if (n == 0) {
            break;
        }

        offset += n;
        buffer->setRange(0, buffer->size() + (size_t)n);
    }

    *out = buffer;
+4 −4
Original line number Diff line number Diff line
@@ -55,6 +55,10 @@ public:
    // Pass a negative value to disable the timeout.
    void setReceiveTimeout(int seconds);

    // Receive a line of data terminated by CRLF, line will be '\0' terminated
    // _excluding_ the termianting CRLF.
    status_t receive_line(char *line, size_t size);

private:
    enum State {
        READY,
@@ -68,10 +72,6 @@ private:

    KeyedVector<string, string> mHeaders;

    // Receive a line of data terminated by CRLF, line will be '\0' terminated
    // _excluding_ the termianting CRLF.
    status_t receive_line(char *line, size_t size);

    HTTPStream(const HTTPStream &);
    HTTPStream &operator=(const HTTPStream &);
};
+8 −0
Original line number Diff line number Diff line
@@ -49,6 +49,11 @@ private:
    off_t mOffset;
    off_t mContentLength;
    bool mContentLengthValid;
    bool mHasChunkedTransferEncoding;

    // The number of data bytes in the current chunk before any subsequent
    // chunk header (or -1 if no more chunks).
    ssize_t mChunkDataBytesLeft;

    status_t connect(
            const char *uri, const String8 &headers, off_t offset);
@@ -58,6 +63,9 @@ private:
            const String8 &headers,
            off_t offset);

    // Read up to "size" bytes of data, respect transfer encoding.
    ssize_t internalRead(void *data, size_t size);

    void applyTimeoutResponse();

    static void MakeFullHeaders(