StreamBuffer StreamBuffer::cut(std::size_t size){ StreamBuffer ret; if(m_size <= size){ ret.swap(*this); } else { AUTO(it, m_chunks.begin()); std::size_t total = 0; // 这是 [m_chunks.begin(), it) 的字节数,不含零头。 while(total < size){ assert(it != m_chunks.end()); const std::size_t remaining = size - total; const std::size_t avail = it->writePos - it->readPos; if(remaining < avail){ AUTO_REF(back, pushBackPooled(ret.m_chunks)); std::memcpy(back.data, it->data + it->readPos, remaining); back.writePos = remaining; it->readPos += remaining; ret.m_size += remaining; m_size -= remaining; break; } total += avail; ++it; } ret.m_chunks.splice(ret.m_chunks.begin(), m_chunks, m_chunks.begin(), it); ret.m_size += total; m_size -= total; } return ret; }
StreamBuffer StreamBuffer::cut_off(std::size_t bytes){ StreamBuffer ret; const AUTO(bytes_to_copy, std::min(bytes, m_size)); if(bytes_to_copy == 0){ return ret; } if(m_size <= bytes_to_copy){ ret.swap(*this); return ret; } std::size_t bytes_copied = 0; AUTO(cut_end, m_first); for(;;){ const AUTO(bytes_remaining, bytes_to_copy - bytes_copied); const AUTO(bytes_avail, cut_end->end - cut_end->begin); if(bytes_remaining <= bytes_avail){ if(bytes_remaining == bytes_avail){ cut_end = cut_end->next; } else { const AUTO(chunk, new Chunk); chunk->next = cut_end; chunk->prev = cut_end->prev; chunk->begin = 0; chunk->end = bytes_remaining; std::memcpy(chunk->data, cut_end->data + cut_end->begin, bytes_remaining); cut_end->begin += bytes_remaining; if(cut_end->prev){ cut_end->prev->next = chunk; } else { m_first = chunk; } cut_end->prev = chunk; } break; } bytes_copied += bytes_avail; cut_end = cut_end->next; } const AUTO(cut_first, m_first); const AUTO(cut_last, cut_end->prev); cut_last->next = NULLPTR; cut_end->prev = NULLPTR; m_first = cut_end; m_size -= bytes_to_copy; ret.m_first = cut_first; ret.m_last = cut_last; ret.m_size = bytes_to_copy; return ret; }
void swap(StreamBuffer &lhs, StreamBuffer &rhs) { lhs.swap(rhs); }
long ClientWriter::put_request(RequestHeaders request_headers, StreamBuffer entity){ PROFILE_ME; StreamBuffer data; data.put(get_string_from_verb(request_headers.verb)); data.put(' '); data.put(request_headers.uri); if(!request_headers.get_params.empty()){ data.put('?'); data.put(url_encoded_from_optional_map(request_headers.get_params)); } char temp[64]; const unsigned ver_major = request_headers.version / 10000, ver_minor = request_headers.version % 10000; unsigned len = (unsigned)std::sprintf(temp, " HTTP/%u.%u\r\n", ver_major, ver_minor); data.put(temp, len); AUTO_REF(headers, request_headers.headers); if(entity.empty()){ headers.erase("Content-Type"); headers.erase("Transfer-Encoding"); if((request_headers.verb == V_POST) || (request_headers.verb == V_PUT)){ headers.set(sslit("Content-Length"), STR_0); } else { headers.erase("Content-Length"); } } else { if(!headers.has("Content-Type")){ headers.set(sslit("Content-Type"), "application/x-www-form-urlencoded; charset=utf-8"); } AUTO(transfer_encoding, headers.get("Transfer-Encoding")); AUTO(pos, transfer_encoding.find(';')); if(pos != std::string::npos){ transfer_encoding.erase(pos); } transfer_encoding = to_lower_case(trim(STD_MOVE(transfer_encoding))); if(transfer_encoding.empty() || (transfer_encoding == STR_IDENTITY)){ headers.set(sslit("Content-Length"), boost::lexical_cast<std::string>(entity.size())); } else { // 只有一个 chunk。 StreamBuffer chunk; len = (unsigned)std::sprintf(temp, "%llx\r\n", (unsigned long long)entity.size()); chunk.put(temp, len); chunk.splice(entity); chunk.put("\r\n0\r\n\r\n"); entity.swap(chunk); } } for(AUTO(it, headers.begin()); it != headers.end(); ++it){ data.put(it->first.get()); data.put(": "); data.put(it->second); data.put("\r\n"); } data.put("\r\n"); data.splice(entity); return on_encoded_data_avail(STD_MOVE(data)); }