| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stdio.h> | 5 #include <stdio.h> |
| 6 #include <stdlib.h> | 6 #include <stdlib.h> |
| 7 #include "ppapi/c/pp_errors.h" | 7 #include "ppapi/c/pp_errors.h" |
| 8 #include "ppapi/c/ppb_instance.h" | 8 #include "ppapi/c/ppb_instance.h" |
| 9 #include "ppapi/cpp/module.h" | 9 #include "ppapi/cpp/module.h" |
| 10 #include "ppapi/cpp/var.h" | 10 #include "ppapi/cpp/var.h" |
| 11 | 11 |
| 12 #include "geturl_handler.h" | 12 #include "url_loader_handler.h" |
| 13 | 13 |
| 14 #ifdef WIN32 | 14 #ifdef WIN32 |
| 15 #undef min | 15 #undef min |
| 16 #undef max | 16 #undef max |
| 17 #undef PostMessage | 17 #undef PostMessage |
| 18 | 18 |
| 19 // Allow 'this' in initializer list | 19 // Allow 'this' in initializer list |
| 20 #pragma warning(disable : 4355) | 20 #pragma warning(disable : 4355) |
| 21 #endif | 21 #endif |
| 22 | 22 |
| 23 GetURLHandler* GetURLHandler::Create(pp::Instance* instance, | 23 URLLoaderHandler* URLLoaderHandler::Create(pp::Instance* instance, |
| 24 const std::string& url) { | 24 const std::string& url) { |
| 25 return new GetURLHandler(instance, url); | 25 return new URLLoaderHandler(instance, url); |
| 26 } | 26 } |
| 27 | 27 |
| 28 GetURLHandler::GetURLHandler(pp::Instance* instance, const std::string& url) | 28 URLLoaderHandler::URLLoaderHandler(pp::Instance* instance, |
| 29 const std::string& url) |
| 29 : instance_(instance), | 30 : instance_(instance), |
| 30 url_(url), | 31 url_(url), |
| 31 url_request_(instance), | 32 url_request_(instance), |
| 32 url_loader_(instance), | 33 url_loader_(instance), |
| 33 buffer_(new char[READ_BUFFER_SIZE]), | 34 buffer_(new char[READ_BUFFER_SIZE]), |
| 34 cc_factory_(this) { | 35 cc_factory_(this) { |
| 35 url_request_.SetURL(url); | 36 url_request_.SetURL(url); |
| 36 url_request_.SetMethod("GET"); | 37 url_request_.SetMethod("GET"); |
| 37 url_request_.SetRecordDownloadProgress(true); | 38 url_request_.SetRecordDownloadProgress(true); |
| 38 } | 39 } |
| 39 | 40 |
| 40 GetURLHandler::~GetURLHandler() { | 41 URLLoaderHandler::~URLLoaderHandler() { |
| 41 delete[] buffer_; | 42 delete[] buffer_; |
| 42 buffer_ = NULL; | 43 buffer_ = NULL; |
| 43 } | 44 } |
| 44 | 45 |
| 45 void GetURLHandler::Start() { | 46 void URLLoaderHandler::Start() { |
| 46 pp::CompletionCallback cc = cc_factory_.NewCallback(&GetURLHandler::OnOpen); | 47 pp::CompletionCallback cc = |
| 48 cc_factory_.NewCallback(&URLLoaderHandler::OnOpen); |
| 47 url_loader_.Open(url_request_, cc); | 49 url_loader_.Open(url_request_, cc); |
| 48 } | 50 } |
| 49 | 51 |
| 50 void GetURLHandler::OnOpen(int32_t result) { | 52 void URLLoaderHandler::OnOpen(int32_t result) { |
| 51 if (result != PP_OK) { | 53 if (result != PP_OK) { |
| 52 ReportResultAndDie(url_, "pp::URLLoader::Open() failed", false); | 54 ReportResultAndDie(url_, "pp::URLLoader::Open() failed", false); |
| 53 return; | 55 return; |
| 54 } | 56 } |
| 55 // Here you would process the headers. A real program would want to at least | 57 // Here you would process the headers. A real program would want to at least |
| 56 // check the HTTP code and potentially cancel the request. | 58 // check the HTTP code and potentially cancel the request. |
| 57 // pp::URLResponseInfo response = loader_.GetResponseInfo(); | 59 // pp::URLResponseInfo response = loader_.GetResponseInfo(); |
| 58 | 60 |
| 59 // Try to figure out how many bytes of data are going to be downloaded in | 61 // Try to figure out how many bytes of data are going to be downloaded in |
| 60 // order to allocate memory for the response body in advance (this will | 62 // order to allocate memory for the response body in advance (this will |
| 61 // reduce heap traffic and also the amount of memory allocated). | 63 // reduce heap traffic and also the amount of memory allocated). |
| 62 // It is not a problem if this fails, it just means that the | 64 // It is not a problem if this fails, it just means that the |
| 63 // url_response_body_.insert() call in GetURLHandler::AppendDataBytes() | 65 // url_response_body_.insert() call in URLLoaderHandler::AppendDataBytes() |
| 64 // will allocate the memory later on. | 66 // will allocate the memory later on. |
| 65 int64_t bytes_received = 0; | 67 int64_t bytes_received = 0; |
| 66 int64_t total_bytes_to_be_received = 0; | 68 int64_t total_bytes_to_be_received = 0; |
| 67 if (url_loader_.GetDownloadProgress(&bytes_received, | 69 if (url_loader_.GetDownloadProgress(&bytes_received, |
| 68 &total_bytes_to_be_received)) { | 70 &total_bytes_to_be_received)) { |
| 69 if (total_bytes_to_be_received > 0) { | 71 if (total_bytes_to_be_received > 0) { |
| 70 url_response_body_.reserve(total_bytes_to_be_received); | 72 url_response_body_.reserve(total_bytes_to_be_received); |
| 71 } | 73 } |
| 72 } | 74 } |
| 73 // We will not use the download progress anymore, so just disable it. | 75 // We will not use the download progress anymore, so just disable it. |
| 74 url_request_.SetRecordDownloadProgress(false); | 76 url_request_.SetRecordDownloadProgress(false); |
| 75 | 77 |
| 76 // Start streaming. | 78 // Start streaming. |
| 77 ReadBody(); | 79 ReadBody(); |
| 78 } | 80 } |
| 79 | 81 |
| 80 void GetURLHandler::AppendDataBytes(const char* buffer, int32_t num_bytes) { | 82 void URLLoaderHandler::AppendDataBytes(const char* buffer, int32_t num_bytes) { |
| 81 if (num_bytes <= 0) | 83 if (num_bytes <= 0) |
| 82 return; | 84 return; |
| 83 // Make sure we don't get a buffer overrun. | 85 // Make sure we don't get a buffer overrun. |
| 84 num_bytes = std::min(READ_BUFFER_SIZE, num_bytes); | 86 num_bytes = std::min(READ_BUFFER_SIZE, num_bytes); |
| 85 // Note that we do *not* try to minimally increase the amount of allocated | 87 // Note that we do *not* try to minimally increase the amount of allocated |
| 86 // memory here by calling url_response_body_.reserve(). Doing so causes a | 88 // memory here by calling url_response_body_.reserve(). Doing so causes a |
| 87 // lot of string reallocations that kills performance for large files. | 89 // lot of string reallocations that kills performance for large files. |
| 88 url_response_body_.insert( | 90 url_response_body_.insert( |
| 89 url_response_body_.end(), buffer, buffer + num_bytes); | 91 url_response_body_.end(), buffer, buffer + num_bytes); |
| 90 } | 92 } |
| 91 | 93 |
| 92 void GetURLHandler::OnRead(int32_t result) { | 94 void URLLoaderHandler::OnRead(int32_t result) { |
| 93 if (result == PP_OK) { | 95 if (result == PP_OK) { |
| 94 // Streaming the file is complete, delete the read buffer since it is | 96 // Streaming the file is complete, delete the read buffer since it is |
| 95 // no longer needed. | 97 // no longer needed. |
| 96 delete[] buffer_; | 98 delete[] buffer_; |
| 97 buffer_ = NULL; | 99 buffer_ = NULL; |
| 98 ReportResultAndDie(url_, url_response_body_, true); | 100 ReportResultAndDie(url_, url_response_body_, true); |
| 99 } else if (result > 0) { | 101 } else if (result > 0) { |
| 100 // The URLLoader just filled "result" number of bytes into our buffer. | 102 // The URLLoader just filled "result" number of bytes into our buffer. |
| 101 // Save them and perform another read. | 103 // Save them and perform another read. |
| 102 AppendDataBytes(buffer_, result); | 104 AppendDataBytes(buffer_, result); |
| 103 ReadBody(); | 105 ReadBody(); |
| 104 } else { | 106 } else { |
| 105 // A read error occurred. | 107 // A read error occurred. |
| 106 ReportResultAndDie( | 108 ReportResultAndDie( |
| 107 url_, "pp::URLLoader::ReadResponseBody() result<0", false); | 109 url_, "pp::URLLoader::ReadResponseBody() result<0", false); |
| 108 } | 110 } |
| 109 } | 111 } |
| 110 | 112 |
| 111 void GetURLHandler::ReadBody() { | 113 void URLLoaderHandler::ReadBody() { |
| 112 // Note that you specifically want an "optional" callback here. This will | 114 // Note that you specifically want an "optional" callback here. This will |
| 113 // allow ReadBody() to return synchronously, ignoring your completion | 115 // allow ReadBody() to return synchronously, ignoring your completion |
| 114 // callback, if data is available. For fast connections and large files, | 116 // callback, if data is available. For fast connections and large files, |
| 115 // reading as fast as we can will make a large performance difference | 117 // reading as fast as we can will make a large performance difference |
| 116 // However, in the case of a synchronous return, we need to be sure to run | 118 // However, in the case of a synchronous return, we need to be sure to run |
| 117 // the callback we created since the loader won't do anything with it. | 119 // the callback we created since the loader won't do anything with it. |
| 118 pp::CompletionCallback cc = | 120 pp::CompletionCallback cc = |
| 119 cc_factory_.NewOptionalCallback(&GetURLHandler::OnRead); | 121 cc_factory_.NewOptionalCallback(&URLLoaderHandler::OnRead); |
| 120 int32_t result = PP_OK; | 122 int32_t result = PP_OK; |
| 121 do { | 123 do { |
| 122 result = url_loader_.ReadResponseBody(buffer_, READ_BUFFER_SIZE, cc); | 124 result = url_loader_.ReadResponseBody(buffer_, READ_BUFFER_SIZE, cc); |
| 123 // Handle streaming data directly. Note that we *don't* want to call | 125 // Handle streaming data directly. Note that we *don't* want to call |
| 124 // OnRead here, since in the case of result > 0 it will schedule | 126 // OnRead here, since in the case of result > 0 it will schedule |
| 125 // another call to this function. If the network is very fast, we could | 127 // another call to this function. If the network is very fast, we could |
| 126 // end up with a deeply recursive stack. | 128 // end up with a deeply recursive stack. |
| 127 if (result > 0) { | 129 if (result > 0) { |
| 128 AppendDataBytes(buffer_, result); | 130 AppendDataBytes(buffer_, result); |
| 129 } | 131 } |
| 130 } while (result > 0); | 132 } while (result > 0); |
| 131 | 133 |
| 132 if (result != PP_OK_COMPLETIONPENDING) { | 134 if (result != PP_OK_COMPLETIONPENDING) { |
| 133 // Either we reached the end of the stream (result == PP_OK) or there was | 135 // Either we reached the end of the stream (result == PP_OK) or there was |
| 134 // an error. We want OnRead to get called no matter what to handle | 136 // an error. We want OnRead to get called no matter what to handle |
| 135 // that case, whether the error is synchronous or asynchronous. If the | 137 // that case, whether the error is synchronous or asynchronous. If the |
| 136 // result code *is* COMPLETIONPENDING, our callback will be called | 138 // result code *is* COMPLETIONPENDING, our callback will be called |
| 137 // asynchronously. | 139 // asynchronously. |
| 138 cc.Run(result); | 140 cc.Run(result); |
| 139 } | 141 } |
| 140 } | 142 } |
| 141 | 143 |
| 142 void GetURLHandler::ReportResultAndDie(const std::string& fname, | 144 void URLLoaderHandler::ReportResultAndDie(const std::string& fname, |
| 143 const std::string& text, | 145 const std::string& text, |
| 144 bool success) { | 146 bool success) { |
| 145 ReportResult(fname, text, success); | 147 ReportResult(fname, text, success); |
| 146 delete this; | 148 delete this; |
| 147 } | 149 } |
| 148 | 150 |
| 149 void GetURLHandler::ReportResult(const std::string& fname, | 151 void URLLoaderHandler::ReportResult(const std::string& fname, |
| 150 const std::string& text, | 152 const std::string& text, |
| 151 bool success) { | 153 bool success) { |
| 152 if (success) | 154 if (success) |
| 153 printf("GetURLHandler::ReportResult(Ok).\n"); | 155 printf("URLLoaderHandler::ReportResult(Ok).\n"); |
| 154 else | 156 else |
| 155 printf("GetURLHandler::ReportResult(Err). %s\n", text.c_str()); | 157 printf("URLLoaderHandler::ReportResult(Err). %s\n", text.c_str()); |
| 156 fflush(stdout); | 158 fflush(stdout); |
| 157 if (instance_) { | 159 if (instance_) { |
| 158 pp::Var var_result(fname + "\n" + text); | 160 pp::Var var_result(fname + "\n" + text); |
| 159 instance_->PostMessage(var_result); | 161 instance_->PostMessage(var_result); |
| 160 } | 162 } |
| 161 } | 163 } |
| OLD | NEW |