RequestProcessorResponseStatus RequestProcessor::ProcessGetStream(Envelope &request, vector<Envelope> &output)
{
    {
        ::zippylog::request_processor::BeginProcessGetStream log;
        LOG_MESSAGE(log, this->logger_sock);
    }

    protocol::request::GetStreamSegmentV1 *get = (protocol::request::GetStreamSegmentV1 *)request.GetMessage(0);
    if (!get) {
        ::zippylog::request_processor::ReceiveInvalidGet log;
        LOG_MESSAGE(log, this->logger_sock);

        this->PopulateErrorResponse(
            protocol::response::UNKNOWN_REQUEST_TYPE,
            "error parsing get message... weird",
            output
        );
        goto LOG_END;
    }

    if (!get->has_path()) {
        ::zippylog::request_processor::ReceiveInvalidGet log;
        LOG_MESSAGE(log, this->logger_sock);

        this->PopulateErrorResponse(
            protocol::response::EMPTY_FIELD,
            "required field 'path' is not set",
            output
        );
        goto LOG_END;
    }

    if (!this->CheckPath(get->path(), output, true, true, true)) goto LOG_END;

    if (!get->has_start_offset()) {
        ::zippylog::request_processor::ReceiveInvalidGet log;
        LOG_MESSAGE(log, this->logger_sock);

        this->PopulateErrorResponse(
            protocol::response::EMPTY_FIELD,
            "required field 'start_offset' is not set",
            output
        );
        goto LOG_END;
    }

    {
        InputStream *stream = this->store->GetInputStream(get->path());
        if (!stream) {
            // we've already verified the stream exists, so there are one of two possibilities:
            //   1) it was deleted between then and now
            //   2) error fetching stream
            // @todo react accordingly
            ::zippylog::request_processor::GetInvalidStream log;
            LOG_MESSAGE(log, this->logger_sock);

            this->PopulateErrorResponse(
                protocol::response::PATH_NOT_FOUND,
                "requested stream could not be found",
                output
            );
            goto LOG_END;
        }

        uint64 start_offset = get->start_offset();
        if (start_offset && !stream->SetAbsoluteOffset(start_offset)) {
            throw Exception("TODO handle error setting offset properly");
        }

        // determine how much to fetch
        uint32 bytes_left = this->get_stream_max_bytes;
        uint32 envelopes_left = this->get_stream_max_envelopes;

        // client can lower server default if it wants
        if (get->has_max_response_bytes() && get->max_response_bytes() < bytes_left) {
            bytes_left = get->max_response_bytes();
        }

        if (get->has_max_response_envelopes() && get->max_response_envelopes() < envelopes_left) {
            envelopes_left = get->max_response_envelopes();
        }

        zippylog::Envelope m = zippylog::Envelope();

        uint32 envelope_size = stream->NextEnvelopeSize();
        ::zippylog::Envelope env;
        // could not find envelope in stream at offset
        if (!envelope_size || !stream->ReadEnvelope(env, envelope_size)) {
            ::zippylog::request_processor::GetInvalidOffset log;
            LOG_MESSAGE(log, this->logger_sock);

            // @todo need better error code
            this->PopulateErrorResponse(
                protocol::response::INVALID_STREAM_OFFSET,
                "no envelopes found at requested stream offset",
                output
            );
            goto LOG_END;
        }

        // we must have an envelope, so start the send sequence
        {
            Envelope start_envelope;
            protocol::response::StreamSegmentStartV1 segment_start;
            segment_start.set_path(get->path());
            segment_start.set_offset(get->start_offset());
            segment_start.add_to_envelope(start_envelope);

            // copy request tags to response for client association
            if (request.TagSize() >= 0) {
                for (int i = 0; i < request.TagSize(); i++) {
                    start_envelope.AddTag(request.GetTag(i));
                }
            }

            output.push_back(start_envelope);
        }

        output.push_back(env);

        uint32 bytes_read = envelope_size;
        uint32 envelopes_read = 1;
        envelopes_left--;

        if (bytes_read < bytes_left && envelopes_left) {
            bytes_left -= envelope_size;

            while (true) {
                envelope_size = stream->NextEnvelopeSize();
                if (!envelope_size) break;

                // @todo we should be resilient and handle stream errors somehow
                if (!stream->ReadEnvelope(env, envelope_size)) break;

                output.push_back(env);

                bytes_read += envelope_size;
                envelopes_read++;

                if (envelope_size > bytes_left) break;
                if (envelopes_left-- == 1) break;
                bytes_left -= envelope_size;
            }
        }

        protocol::response::StreamSegmentEndV1 segment_end;
        segment_end.set_envelopes_sent(envelopes_read);
        segment_end.set_bytes_sent(bytes_read);
        // @todo not all stores might share this concept of offsets
        segment_end.set_offset(stream->CurrentEnvelopeOffset());

        env = ::zippylog::Envelope();
        segment_end.add_to_envelope(&env);
        output.push_back(env);
    }

LOG_END:

    ::zippylog::request_processor:: EndProcessGetStream logend;
    LOG_MESSAGE(logend, this->logger_sock);

    return AUTHORITATIVE;
}