PageRenderTime 382ms CodeModel.GetById 86ms app.highlight 197ms RepoModel.GetById 91ms app.codeStats 1ms

/mordor/streams/http.h

http://github.com/mozy/mordor
C Header | 119 lines | 68 code | 16 blank | 35 comment | 0 complexity | b40c1892cab230724ba78b683f80db9e MD5 | raw file
  1#ifndef __MORDOR_HTTP_STREAM__
  2#define __MORDOR_HTTP_STREAM__
  3// Copyright (c) 2009 - Mozy, Inc.
  4
  5#include "filter.h"
  6#include "mordor/exception.h"
  7#include "mordor/future.h"
  8#include "mordor/http/broker.h"
  9
 10namespace Mordor {
 11
 12struct EntityChangedException : virtual Exception {};
 13
 14/// @note When using HTTPStream for PUTs, automatic retry is not supported
 15/// (since HTTPStream does not see the entire request body in a single call,
 16/// the retry must be handled at a higher level).
 17class HTTPStream : public FilterStream
 18{
 19public:
 20    typedef boost::shared_ptr<HTTPStream> ptr;
 21
 22public:
 23    HTTPStream(const URI &uri, HTTP::RequestBroker::ptr requestBroker,
 24        boost::function<bool (size_t)> delayDg = NULL);
 25    HTTPStream(const HTTP::Request &requestHeaders,
 26        HTTP::RequestBroker::ptr requestBroker,
 27        boost::function<bool (size_t)> delayDg = NULL);
 28    ~HTTPStream();
 29
 30    void sharedRetryCounter(size_t *retries) { mp_retries = retries; }
 31
 32    void eTag(const HTTP::ETag &eTag) { m_eTag = eTag; }
 33    HTTP::ETag eTag();
 34
 35    /// Force the transfer to begin (i.e. so a call to size() won't try to
 36    /// do an extra HEAD)
 37    ///
 38    /// @note If the current read advice is zero, this will be forced to do an
 39    /// HTTP request for the entire entity
 40    void start();
 41    /// This will abandon any current transfer in progress.  If it returns
 42    /// true, the transfer will have already begun at the current position
 43    bool checkModified();
 44    /// @note In WRITE mode, HTTP response is not available until stream close.
 45    /// It will cause write abortion if this interface is invoked before stream close
 46    const HTTP::Response &response();
 47
 48    bool supportsRead() { return true; }
 49    bool supportsWrite() { return true; }
 50    bool supportsSeek() { return true; }
 51    bool supportsSize();
 52    bool supportsTruncate() { return true; }
 53    bool supportsTell() { return true; }
 54
 55    void close(CloseType type = BOTH);
 56
 57    using FilterStream::read;
 58    size_t read(Buffer &buffer, size_t length);
 59    using FilterStream::write;
 60    size_t write(const Buffer &buffer, size_t length);
 61    long long seek(long long offset, Anchor anchor = BEGIN);
 62    long long size();
 63    /// @note Truncate is accomplished by doing a PUT with
 64    /// Content-Range: */<size>.
 65    void truncate(long long size);
 66    void flush(bool flushParent = true);
 67
 68    /// Advise about subsequent read calls, so that more efficient HTTP
 69    /// requests can be used.
 70    ///
 71    /// Sets the minimum number of bytes per HTTP request.  The default is
 72    /// ~0ull, which means only one HTTP request will be needed.  Setting to 0
 73    /// would mean each call to read will generate a new HTTP request.
 74    void adviseRead(unsigned long long advice) { m_readAdvice = advice; }
 75    /// Advise about subsequent write calls, so that more efficient HTTP
 76    /// requests can be used.
 77    ///
 78    /// Sets the minimum number of bytes per HTTP request.  The default is
 79    /// ~0ull, which means only one HTTP request will be needed.  Setting to 0
 80    /// would mean each call to write will generate a new HTTP request.
 81    /// @warning If you write beyond the initial advice, you will invoke
 82    /// non-standardized HTTP behavior that most servers will not support.
 83    /// See http://code.google.com/p/gears/wiki/ContentRangePostProposal
 84    /// and http://www.hpl.hp.com/personal/ange/archives/archives-97/http-wg-archive/2530.html
 85    void adviseWrite(unsigned long long advice) { m_writeAdvice = advice; }
 86    /// Advise about the eventual size of the stream, so that a more efficient
 87    /// HTTP request can be used.
 88    ///
 89    /// Setting this will avoid using chunked encoding.
 90    void adviseSize(long long advice) { m_sizeAdvice = advice; }
 91
 92private:
 93    void start(size_t length);
 94    void stat();
 95    void doWrite(boost::shared_ptr<HTTP::ClientRequest> request);
 96    void startWrite();
 97    void clearParent(bool error = false);
 98
 99private:
100    HTTP::Request m_requestHeaders;
101    HTTP::Response m_response;
102    bool m_hasResponse;
103    HTTP::RequestBroker::ptr m_requestBroker;
104    HTTP::ETag m_eTag;
105    long long m_pos, m_size, m_sizeAdvice;
106    unsigned long long m_readAdvice, m_writeAdvice,
107        m_readRequested, m_writeRequested;
108    boost::function<bool (size_t)> m_delayDg;
109    size_t *mp_retries;
110    bool m_writeInProgress, m_abortWrite;
111    Future<> m_writeFuture, m_writeFuture2;
112    boost::shared_ptr<HTTP::ClientRequest> m_writeRequest;
113    boost::shared_ptr<HTTP::ClientRequest> m_readRequest;
114    boost::exception_ptr m_writeException;
115};
116
117}
118
119#endif