Hello andreip,
I'd like you to do a code review. Please execute
g4 diff -c 9185258
or point your web browser to
http://mondrian/9185258
to review the following code:
Change 9185258 by [EMAIL PROTECTED] on 2008/11/27 13:10:24 *pending*
Adds OPHttpRequest. Mailed on behalf of Opera. Note that this depends
on pending CL 9135600.
R=andreip
[EMAIL PROTECTED],[EMAIL PROTECTED]
DELTA=550 (435 added, 58 deleted, 57 changed)
OCL=9185258
Affected files ...
...
//depot/googleclient/gears/opensource/gears/localserver/opera/http_request_op.cc#1
edit
...
//depot/googleclient/gears/opensource/gears/localserver/opera/http_request_op.h#1
edit
550 delta lines: 435 added, 58 deleted, 57 changed
Also consider running:
g4 lint -c 9185258
which verifies that the changelist doesn't introduce new style violations.
If you can't do the review, please let me know as soon as possible. During
your review, please ensure that all new code has corresponding unit tests and
that existing unit tests are updated appropriately. Visit
http://www/eng/code_review.html for more information.
This is a semiautomated message from "g4 mail". Complaints or suggestions?
Mail [EMAIL PROTECTED]
Change 9185258 by [EMAIL PROTECTED] on 2008/11/27 13:10:24 *pending*
Adds OPHttpRequest. Note that this depends on pending CL 9135600.
Affected files ...
...
//depot/googleclient/gears/opensource/gears/localserver/opera/http_request_op.cc#1
edit
...
//depot/googleclient/gears/opensource/gears/localserver/opera/http_request_op.h#1
edit
====
//depot/googleclient/gears/opensource/gears/localserver/opera/http_request_op.cc#1
-
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/localserver/opera/http_request_op.cc
====
# action=edit type=text
--- googleclient/gears/opensource/gears/localserver/opera/http_request_op.cc
2008-11-27 13:10:19.000000000 +0000
+++ googleclient/gears/opensource/gears/localserver/opera/http_request_op.cc
2008-11-27 13:28:28.000000000 +0000
@@ -23,74 +23,143 @@
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <msxml2.h>
+#include <algorithm>
+#include <vector>
+
#include "gears/localserver/opera/http_request_op.h"
+#include "gears/base/common/byte_store.h"
+#include "gears/base/common/string_utils.h"
+#include "gears/base/common/thread_locals.h"
+#include "gears/base/common/url_utils.h"
+#include "gears/base/npapi/browser_utils.h"
+#include "gears/base/opera_mobile/opera_utils.h"
+#include "gears/blob/blob_interface.h"
+#include "gears/blob/blob_stream_ie.h"
+#include "gears/blob/buffer_blob.h"
+#include "gears/localserver/common/safe_http_request.h"
//------------------------------------------------------------------------------
// Create
//------------------------------------------------------------------------------
// static
bool HttpRequest::Create(scoped_refptr<HttpRequest>* request) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
+ if (OperaUtils::GetMainThreadId() ==
+ ThreadMessageQueue::GetInstance()->GetCurrentThreadId()) {
+ OPHttpRequest *op_request = new OPHttpRequest();
+ if (!op_request) {
+ LOG16((L"HttpRequest::Create - CreateInstance failed\n"));
+ return false;
+ }
+ request->reset(op_request);
+ return true;
+ } else {
+ return HttpRequest::CreateSafeRequest(request);
+ }
}
// static
bool HttpRequest::CreateSafeRequest(scoped_refptr<HttpRequest>* request) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
-}
+ request->reset(new SafeHttpRequest(OperaUtils::GetMainThreadId()));
+ return true;
+}
+
+
+//------------------------------------------------------------------------------
+// AsyncFunctor implementation
+//------------------------------------------------------------------------------
+
+class OPHttpRequest_AsyncFunctor
+ : public AsyncFunctor {
+ public:
+ OPHttpRequest_AsyncFunctor(OPHttpRequest *request)
+ : request_(request) {
+ request->Ref();
+ }
+
+ ~OPHttpRequest_AsyncFunctor() {
+ request_->Unref();
+ }
+
+ virtual void Run() {
+ request_->Run();
+ }
+
+ private:
+ OPHttpRequest *request_;
+};
//------------------------------------------------------------------------------
// Construction, destruction and refcounting
//------------------------------------------------------------------------------
-OPHttpRequest::OPHttpRequest() {
- // TODO(steveblock): Implement me.
- assert(false);
-}
-
-OPHttpRequest::~OPHttpRequest() {
- // TODO(steveblock): Implement me.
- assert(false);
+
+OPHttpRequest::OPHttpRequest()
+ : ref_count_(0), caching_behavior_(USE_ALL_CACHES),
+ redirect_behavior_(FOLLOW_ALL), was_redirected_(false),
+ url_data_(NULL),
+ was_aborted_(false), listener_(NULL), ready_state_(UNINITIALIZED),
+ has_synthesized_response_payload_(false), actual_data_size_(0),
+ async_(false) {
+}
+
+/*virtual*/ OPHttpRequest::~OPHttpRequest() {
+ if (url_data_) {
+ url_data_->OnCompleted();
+ url_data_ = NULL;
+ }
+
+ for (req_header_iter_ = request_headers_.begin();
+ req_header_iter_ != request_headers_.end(); req_header_iter_++) {
+ delete *req_header_iter_;
+ }
+}
+
+HRESULT OPHttpRequest::FinalConstruct() {
+ return S_OK;
+}
+
+void OPHttpRequest::FinalRelease() {
}
void OPHttpRequest::Ref() {
- // TODO(steveblock): Implement me.
- assert(false);
+ ref_count_++;
}
void OPHttpRequest::Unref() {
- // TODO(steveblock): Implement me.
- assert(false);
+ assert(ref_count_ > 0);
+ ref_count_--;
+ if (ref_count_ == 0)
+ delete this;
}
//------------------------------------------------------------------------------
// GetReadyState
//------------------------------------------------------------------------------
bool OPHttpRequest::GetReadyState(ReadyState *state) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
+ *state = ready_state_;
+ return true;
}
//------------------------------------------------------------------------------
// GetResponseBody
//------------------------------------------------------------------------------
bool OPHttpRequest::GetResponseBody(scoped_refptr<BlobInterface>* blob) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
+ if (!IsInteractiveOrComplete() || was_aborted_)
+ return false;
+
+ response_body_->CreateBlob(blob);
+ return true;
}
//------------------------------------------------------------------------------
// GetStatus
//------------------------------------------------------------------------------
bool OPHttpRequest::GetStatus(int *status) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
+ if (!IsInteractiveOrComplete() || was_aborted_)
+ return false;
+ *status = response_payload_.status_code;
+ return true;
}
//------------------------------------------------------------------------------
@@ -98,91 +167,44 @@
// TODO(michaeln): remove this method from the interface, prefer getStatusLine
//------------------------------------------------------------------------------
bool OPHttpRequest::GetStatusText(std::string16 *status_text) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
+ if (!IsInteractiveOrComplete() || was_aborted_)
+ return false;
+ return ParseHttpStatusLine(response_payload_.status_line,
+ NULL, NULL, status_text);
}
//------------------------------------------------------------------------------
// GetStatusLine
//------------------------------------------------------------------------------
bool OPHttpRequest::GetStatusLine(std::string16 *status_line) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
-}
-
-//------------------------------------------------------------------------------
-// WasRedirected
-//------------------------------------------------------------------------------
-bool OPHttpRequest::WasRedirected() {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
-}
-
-//------------------------------------------------------------------------------
-// GetFinalUrl
-//------------------------------------------------------------------------------
-bool OPHttpRequest::GetFinalUrl(std::string16 *full_url) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
-}
-
-//------------------------------------------------------------------------------
-// GetInitialUrl
-//------------------------------------------------------------------------------
-bool OPHttpRequest::GetInitialUrl(std::string16 *full_url) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
-}
-
-//------------------------------------------------------------------------------
-// Open
-//------------------------------------------------------------------------------
-bool OPHttpRequest::Open(const char16 *method, const char16* url, bool async,
- BrowsingContext *browsing_context) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
-}
-
-//------------------------------------------------------------------------------
-// SetRequestHeader
-//------------------------------------------------------------------------------
-bool OPHttpRequest::SetRequestHeader(const char16* name, const char16* value) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
-}
-
-//------------------------------------------------------------------------------
-// Send
-//------------------------------------------------------------------------------
-bool OPHttpRequest::Send(BlobInterface *blob) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
+ if (!IsInteractiveOrComplete() || was_aborted_)
+ return false;
+ *status_line = response_payload_.status_line;
+ return true;
}
//------------------------------------------------------------------------------
// GetAllResponseHeaders
//------------------------------------------------------------------------------
bool OPHttpRequest::GetAllResponseHeaders(std::string16 *headers) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
-}
-
-//------------------------------------------------------------------------------
-// GetResponseCharset
-//------------------------------------------------------------------------------
+ if (!IsInteractiveOrComplete() || was_aborted_)
+ return false;
+ headers->assign(response_payload_.headers);
+ return true;
+}
+
std::string16 OPHttpRequest::GetResponseCharset() {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
+ if (url_data_) {
+ const char *charset = NULL;
+ url_data_->GetResponseCharset(charset);
+
+ std::string16 charset16;
+ if (charset)
+ UTF8ToString16(charset, strlen(charset), &charset16);
+ return charset16;
+ }
+
+ return std::string16();
}
//------------------------------------------------------------------------------
@@ -190,18 +212,264 @@
//------------------------------------------------------------------------------
bool OPHttpRequest::GetResponseHeader(const char16* name,
std::string16 *value) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
-}
-
+ if (!IsInteractiveOrComplete() || was_aborted_)
+ return false;
+ return response_payload_.GetHeader(name, value);
+}
+
+//------------------------------------------------------------------------------
+// Open
+//------------------------------------------------------------------------------
+bool OPHttpRequest::Open(const char16 *method, const char16* url, bool async,
+ BrowsingContext *browsing_context) {
+ assert(!IsRelativeUrl(url));
+ if (!IsUninitialized())
+ return false;
+
+ async_ = async;
+ url_ = url;
+ if (!origin_.InitFromUrl(url)) {
+ return false;
+ }
+ browsing_context_.reset(browsing_context);
+
+ req_header_iter_ = request_headers_.end();
+
+ method_ = method;
+ UpperString(method_);
+
+ SetReadyState(HttpRequest::OPEN);
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// SetRequestHeader
+// Here we gather additional request headers to be sent.
+//------------------------------------------------------------------------------
+bool OPHttpRequest::SetRequestHeader(const char16* name, const char16* value) {
+ if (!IsOpen())
+ return false;
+
+ HeaderEntry *new_header = new HeaderEntry;
+ if (!new_header)
+ return false;
+
+ new_header->name.assign(name);
+ new_header->value.assign(value);
+ request_headers_.push_back(new_header);
+ req_header_iter_ = request_headers_.begin();
+
+ return true;
+}
+
+bool OPHttpRequest::WasRedirected() {
+ return IsInteractiveOrComplete() && !was_aborted_ && was_redirected_;
+}
+
+bool OPHttpRequest::GetFinalUrl(std::string16 *full_url) {
+ if (!IsInteractiveOrComplete() || was_aborted_)
+ return false;
+
+ if (WasRedirected())
+ *full_url = redirect_url_;
+ else
+ *full_url = url_;
+ return true;
+}
+
+bool OPHttpRequest::GetInitialUrl(std::string16 *full_url) {
+ *full_url = url_; // may be empty if request has not occurred
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// Send
+//------------------------------------------------------------------------------
+bool OPHttpRequest::Send(BlobInterface* blob) {
+ post_data_.reset(blob ? blob : new EmptyBlob);
+ post_data_offset_ = 0;
+ if (IsPostOrPut()) {
+ std::string16 size_str =
Integer64ToString16(post_data_?post_data_->Length():0);
+ SetRequestHeader(HttpConstants::kContentLengthHeader, size_str.c_str());
+ }
+
+ return SendImpl();
+}
+
+bool OPHttpRequest::SendImpl() {
+ if (!IsOpen() || url_.empty() || !browsing_context_.get())
+ return false;
+
+ OpGearsAPI *opera_api = OperaUtils::GetGearsApi();
+ if (opera_api) {
+ // TODO([EMAIL PROTECTED]): Add BrowsingContext or equivalent to provide
+ // access to the JS context.
+ //opera_api->RequestUrl(browsing_context_->GetJsContext(), this, this);
+ }
+
+ return !was_aborted_;
+}
+
+/*virtual*/ bool OPHttpRequest::GetNextReqHeader(const unsigned short *&name,
+
const unsigned short *&value)
+{
+ if (req_header_iter_ == request_headers_.end())
+ return false;
+
+ name = (*req_header_iter_)->name.c_str();
+ value = (*req_header_iter_)->value.c_str();
+
+ req_header_iter_++;
+
+ return true;
+}
+
+/*virtual*/ const wchar_t*
+OPHttpRequest::GetUrl()
+{
+ return url_.c_str();
+}
+
+/*virtual*/ const unsigned short*
+OPHttpRequest::GetMethod()
+{
+ return method_.c_str();
+}
+
+/*virtual*/ long
+OPHttpRequest::GetPostData(unsigned char* buffer, long max_size)
+{
+ int64 read;
+ // max_size of -1 is interpreted as a query for the size of the data
+ if (max_size == -1) {
+ read = post_data_.get()->Length();
+ if (read > LONG_MAX)
+ return -1; // -1 returned means too long for long
+ }
+ else {
+ read = post_data_.get()->Read(buffer, post_data_offset_, max_size);
+ post_data_offset_ += read;
+ }
+
+ // safe cast since max_size is a long value the return value cannot be larger
+ // than long and there is a check in the Length() calculation already
+ return (long)read;
+}
+
+/*virtual*/ void OPHttpRequest::OnDataReceived()
+{
+ if (ready_state_ == HttpRequest::OPEN) {
+ DWORD status_code = url_data_->GetStatus();
+ // Initialize the payload
+ LOG16((L"OPHttpRequest::OnDataReceived (%d)\n", status_code));
+ // Be careful not to overwrite a redirect response synthesized in
OnRedirect
+ if (has_synthesized_response_payload_) {
+ return;
+ }
+
+ response_payload_.status_code = status_code;
+
+ const char *status_line;
+ url_data_->GetStatusText(status_line);
+ if (status_line)
+ UTF8ToString16(status_line, strlen(status_line),
+ &response_payload_.status_line);
+
+ const char *response_headers;
+ url_data_->GetResponseHeaders(response_headers);
+ if (response_headers)
+ UTF8ToString16(response_headers, strlen(response_headers),
+ &response_payload_.headers);
+
+ actual_data_size_ = 0;
+ response_body_.reset(new ByteStore);
+
+ SetReadyState(HttpRequest::INTERACTIVE);
+ }
+
+ if (url_data_) {
+ const char *content;
+ unsigned long content_length;
+ url_data_->GetBodyText(content, content_length);
+
+ if (content_length && content) {
+ // Append the new data to the payload
+ response_body_->AddData(content, content_length);
+
+ if (listener_)
+ listener_->DataAvailable(this,
response_body_->Length());//prev_pos);
+ }
+ }
+
+ if (!url_data_ || url_data_->IsFinished()) {
+ if (async_) {
+
AsyncRouter::GetInstance()->CallAsync(ThreadMessageQueue::GetInstance()->
+
GetCurrentThreadId(),
+
new OPHttpRequest_AsyncFunctor(this));
+ }
+ else {
+ SetReadyState(HttpRequest::COMPLETE);
+ }
+
+ // reset data source so that we avoid more calls to this
+ // object after we have finised.
+ if (url_data_) {
+ url_data_->OnCompleted();
+ url_data_ = NULL;
+ }
+ }
+}
+
+/*virtual*/ OpHTTPListener::RedirectStatus
+OPHttpRequest::OnRedirected(const unsigned short* redirect_url)
+{
+ bool follow = false;
+ switch (redirect_behavior_) {
+ case FOLLOW_ALL:
+ follow = true;
+ break;
+
+ case FOLLOW_NONE:
+ follow = false;
+ break;
+
+ case FOLLOW_WITHIN_ORIGIN:
+ follow = origin_.IsSameOriginAsUrl(redirect_url);
+ break;
+ }
+
+ if (!follow)
+ return OpHTTPListener::REDIRECT_CANCEL;
+ was_redirected_ = true;
+ redirect_url_ = redirect_url;
+ return OpHTTPListener::REDIRECT_OK;
+}
+
+/*virtual*/ void OPHttpRequest::OnError(OpHTTPListener::LoadingError err)
+{
+ Abort();
+}
+
+/*virtual*/ void OPHttpRequest::OnRequestCreated(OpUrlData* data)
+{
+ url_data_ = data;
+}
+
+/*virtual*/ void OPHttpRequest::OnRequestDestroyed()
+{
+ url_data_ = NULL;
+}
//------------------------------------------------------------------------------
// Abort
//------------------------------------------------------------------------------
bool OPHttpRequest::Abort() {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
+ if (url_data_) {
+ url_data_->OnCompleted();
+ url_data_ = NULL;
+ }
+// g_opera->AbortUrl(url_id_);
+ was_aborted_ = true;
+ return true;
}
//------------------------------------------------------------------------------
@@ -209,7 +477,20 @@
//------------------------------------------------------------------------------
bool OPHttpRequest::SetListener(HttpListener *listener,
bool enable_data_available) {
- // TODO(steveblock): Implement me.
- assert(false);
- return false;
-}
+ listener_ = listener;
+ listener_data_available_enabled_ = enable_data_available;
+ return true;
+}
+
+void OPHttpRequest::SetReadyState(ReadyState state) {
+ if (state > ready_state_) {
+ ready_state_ = state;
+ if (listener_) {
+ listener_->ReadyStateChanged(this);
+ }
+ }
+}
+
+void OPHttpRequest::Run() {
+ SetReadyState(HttpRequest::COMPLETE);
+}
====
//depot/googleclient/gears/opensource/gears/localserver/opera/http_request_op.h#1
-
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/localserver/opera/http_request_op.h
====
# action=edit type=text
--- googleclient/gears/opensource/gears/localserver/opera/http_request_op.h
2008-11-27 13:10:19.000000000 +0000
+++ googleclient/gears/opensource/gears/localserver/opera/http_request_op.h
2008-11-27 13:19:05.000000000 +0000
@@ -26,12 +26,23 @@
#ifndef GEARS_LOCALSERVER_OPERA_HTTP_REQUEST_OP_H__
#define GEARS_LOCALSERVER_OPERA_HTTP_REQUEST_OP_H__
+#include <string>
+#include <vector>
+#include "gears/base/common/async_router.h"
+#include "gears/base/common/atl_headers_win32.h"
+#include "gears/base/common/security_model.h"
+#include "gears/base/common/scoped_refptr.h"
#include "gears/localserver/common/http_request.h"
-
+#include "gears/localserver/common/localserver_db.h"
+#include "third_party/opera_mobile/opera_callback_api.h"
class BlobInterface;
-
-class OPHttpRequest : public HttpRequest {
+class ByteStore;
+
+class OPHttpRequest
+ : public HttpRequest,
+ public OpHTTPRequestDataProviderInterface,
+ public OpHTTPListener {
public:
OPHttpRequest();
virtual ~OPHttpRequest();
@@ -96,9 +107,52 @@
// events
virtual bool SetListener(HttpListener *listener, bool enable_data_available);
+ HRESULT FinalConstruct();
+ void FinalRelease();
+
+ virtual bool IsAsync() { return async_; }
+ virtual bool GetNextReqHeader(const unsigned short *&name,
+
const unsigned short *&value);
+ virtual const wchar_t* GetUrl();
+ virtual const unsigned short* GetMethod();
+ virtual long GetPostData(unsigned char* buffer, long
max_size);
+
+ virtual void OnDataReceived();
+ virtual RedirectStatus OnRedirected(const unsigned short* redirect_url);
+ virtual void OnError(LoadingError err);
+ virtual void OnRequestCreated(OpUrlData* data);
+ virtual void OnRequestDestroyed();
+
+ void Run();
+
private:
+ class HeaderEntry {
+ public:
+ std::string16 name;
+ std::string16 value;
+ };
+
+ bool SendImpl();
+ HRESULT OnRedirect(const char16 *redirect_url);
+ void SetReadyState(ReadyState state);
bool IsUninitialized() { return ready_state_ == HttpRequest::UNINITIALIZED; }
bool IsOpen() { return ready_state_ == HttpRequest::OPEN; }
+ bool IsSent() { return ready_state_ == HttpRequest::SENT; }
+ bool IsInteractive() { return ready_state_ == HttpRequest::INTERACTIVE; }
+ bool IsComplete() { return ready_state_ == HttpRequest::COMPLETE; }
+ bool IsInteractiveOrComplete() { return IsInteractive() || IsComplete(); }
+ bool IsPostOrPut() {
+ return method_ == L"POST" || method_ == L"PUT";
+ }
+
+ int ref_count_;
+
+ // The (non-relative) request url
+ std::string16 url_;
+ SecurityOrigin origin_;
+
+ // Whether the request should be performed asynchronously
+ bool async_;
// Whether to bypass caches
CachingBehavior caching_behavior_;
@@ -109,8 +163,50 @@
// Whether to send cookies or not
CookieBehavior cookie_behavior_;
+ // The request method
+ std::string16 method_;
+
+ // The POST data
+ scoped_refptr<BlobInterface> post_data_;
+ std::string post_data_string_;
+ int64 post_data_offset_;
+
+ // Additional request headers we've been asked to send with the request
+ std::vector<HeaderEntry*> request_headers_;
+ std::vector<HeaderEntry*>::iterator req_header_iter_;
+
// Our XmlHttpRequest like ready state, 0 thru 4
ReadyState ready_state_;
+
+ // Whether this request was aborted
+ bool was_aborted_;
+
+ // Whether or not we have been redirected
+ bool was_redirected_;
+
+ // If we've been redirected, the location of the redirect. If we experience
+ // a chain of redirects, this will be the last in the chain upon completion.
+ std::string16 redirect_url_;
+
+ OpUrlData *url_data_;
+
+ // Our listener
+ HttpRequest::HttpListener *listener_;
+ bool listener_data_available_enabled_;
+
+ // We populate this structure with various pieces of response data:
+ // status code, status line, headers, data
+ WebCacheDB::PayloadInfo response_payload_;
+ scoped_refptr<ByteStore> response_body_;
+
+ bool has_synthesized_response_payload_;
+
+ // The amount of data we've read into the response_payload_.data
+ // Initially the stl vector is allocated to a large size. We keep
+ // track of how much of that allocated space is actually used here.
+ size_t actual_data_size_;
+
+ scoped_refptr<BrowsingContext> browsing_context_;
};
#endif // GEARS_LOCALSERVER_OPERA_HTTP_REQUEST_OP_H__