Chromium Code Reviews
|
| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // This example shows how to use the URLLoader in streaming mode (reading to | |
| 6 // memory as data comes over the network). This example uses PostMessage between | |
| 7 // the plugin and the url_loader.html page in this directory to start the load | |
| 8 // and to communicate the result. | |
| 9 // | |
| 10 // The other mode is to stream to a file instead. For that mode, call | |
| 11 // URLLoader.FinishSthreamingToFile once the "Open" callback is complete, and | |
| 12 // then call URLResponseInfo.GetBodyAsFileRef once the file stream is complete. | |
| 13 // Stream-to-file is simpler, but won't allow you to get partial data as it | |
|
darin (slow to review)
2011/07/09 04:01:27
This is not exactly true. You can open the file f
| |
| 14 // comes over the network. | |
| 15 | |
| 16 #include "ppapi/cpp/completion_callback.h" | |
| 17 #include "ppapi/cpp/instance.h" | |
| 18 #include "ppapi/cpp/module.h" | |
| 19 #include "ppapi/cpp/url_loader.h" | |
| 20 #include "ppapi/cpp/url_request_info.h" | |
| 21 #include "ppapi/cpp/url_response_info.h" | |
| 22 | |
| 23 // Buffer size for reading network data. | |
| 24 const int kBufSize = 1024; | |
|
darin (slow to review)
2011/07/09 04:01:27
nit: 'static'
| |
| 25 | |
| 26 class MyInstance : public pp::Instance { | |
| 27 public: | |
| 28 explicit MyInstance(PP_Instance instance) | |
| 29 : pp::Instance(instance) { | |
| 30 factory_.Initialize(this); | |
| 31 } | |
| 32 virtual ~MyInstance() { | |
| 33 // Make sure to explicitly close the loader. If somebody else is holding a | |
| 34 // reference to the URLLoader object when this class goes out of scope (so | |
| 35 // the URLLoader outlives "this"), and you have an outstanding read | |
| 36 // request, the URLLoader will write into invalid memory. | |
| 37 loader_.Close(); | |
| 38 } | |
| 39 | |
| 40 // Handler for the page sending us messages. | |
| 41 virtual void HandleMessage(const pp::Var& message_data); | |
| 42 | |
| 43 private: | |
| 44 // Called to initiate the request. | |
| 45 void StartRequest(const std::string& url); | |
| 46 | |
| 47 // Callback for the URLLoader to tell us it finished opening the connection. | |
| 48 void OnOpenComplete(int32_t result); | |
| 49 | |
| 50 // Starts streaming data. | |
| 51 void ReadMore(); | |
| 52 | |
| 53 // Callback for the URLLoader to tell us when it finished a read. | |
| 54 void OnReadComplete(int32_t result); | |
| 55 | |
| 56 // Forwards the given string to the page. | |
| 57 void ReportResponse(const std::string& data); | |
| 58 | |
| 59 // Generates completion callbacks scoped to this class. | |
| 60 pp::CompletionCallbackFactory<MyInstance> factory_; | |
| 61 | |
| 62 pp::URLLoader loader_; | |
| 63 pp::URLResponseInfo response_; | |
| 64 | |
| 65 // The buffer used for the current read request. This is filled and then | |
| 66 // copied into content_ to build up the entire document. | |
| 67 char buf_[kBufSize]; | |
| 68 | |
| 69 // All the content loaded so far. | |
| 70 std::string content_; | |
| 71 }; | |
| 72 | |
| 73 void MyInstance::HandleMessage(const pp::Var& message_data) { | |
| 74 if (message_data.is_string() && message_data.AsString() == "go") | |
| 75 StartRequest("./fetched_content.html"); | |
| 76 } | |
| 77 | |
| 78 void MyInstance::StartRequest(const std::string& url) { | |
| 79 content_.clear(); | |
| 80 | |
| 81 pp::URLRequestInfo request(this); | |
| 82 request.SetURL(url); | |
| 83 request.SetMethod("GET"); | |
| 84 | |
| 85 loader_ = pp::URLLoader(this); | |
| 86 loader_.Open(request, | |
| 87 factory_.NewRequiredCallback(&MyInstance::OnOpenComplete)); | |
| 88 } | |
| 89 | |
| 90 void MyInstance::OnOpenComplete(int32_t result) { | |
| 91 if (result != PP_OK) { | |
| 92 ReportResponse("URL could not be requested"); | |
| 93 return; | |
| 94 } | |
| 95 | |
| 96 response_ = loader_.GetResponseInfo(); | |
| 97 | |
| 98 // Here you would process the headers. A real program would want to at least | |
| 99 // check the HTTP code and potentially cancel the request. | |
| 100 | |
| 101 // Start streaming. | |
| 102 ReadMore(); | |
| 103 } | |
| 104 | |
| 105 void MyInstance::ReadMore() { | |
| 106 // Note that you specifically want an "optional" callback here. This will | |
| 107 // allow Read() to return synchronously, ignoring your completion callback, | |
| 108 // if data is available. For fast connections and large files, reading as | |
| 109 // fast as we can will make a large performance difference. However, in the | |
| 110 // case of a synchronous return, we need to be sure to delete our callback | |
|
darin (slow to review)
2011/07/09 04:01:27
you say "be sure to delete our callback", but you
| |
| 111 // since the loader won't do anything with it. | |
| 112 pp::CompletionCallback cc = | |
| 113 factory_.NewOptionalCallback(&MyInstance::OnReadComplete); | |
| 114 int32_t result = PP_OK; | |
| 115 do { | |
| 116 result = loader_.ReadResponseBody(buf_, kBufSize, cc); | |
| 117 // Handle streaming data directly. Note that we *don't* want to call | |
| 118 // OnReadComplete here, since in the case of result > 0 it will schedule | |
| 119 // another call to this function. If the network is very fast, we could | |
| 120 // end up with a deeply recursive stack. | |
| 121 if (result > 0) | |
| 122 content_.append(buf_, result); | |
| 123 } while (result > 0); | |
| 124 | |
| 125 // Either we reached the end of the stream or there was an error. We want | |
|
darin (slow to review)
2011/07/09 04:01:27
It might help to say: "we reached the end of the
| |
| 126 // OnReadComplete to get called no matter what to handle that case, whether | |
| 127 // the error is synchronous or asynchronous. If the result code *is* | |
| 128 // COMPLETIONPENDING, our callback will be called asynchronously. | |
| 129 if (result != PP_OK_COMPLETIONPENDING) | |
| 130 cc.Run(result); | |
| 131 } | |
| 132 | |
| 133 void MyInstance::OnReadComplete(int32_t result) { | |
| 134 if (result == PP_OK) { | |
| 135 // Streaming the file is complete. | |
| 136 ReportResponse(content_); | |
| 137 } else if (result > 0) { | |
| 138 // The URLLoader just filled "result" number of bytes into our buffer. | |
| 139 // Save them and perform another read. | |
| 140 content_.append(buf_, result); | |
| 141 ReadMore(); | |
| 142 } else { | |
| 143 // A read error occurred. | |
| 144 ReportResponse("A read error occurred"); | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 void MyInstance::ReportResponse(const std::string& data) { | |
| 149 PostMessage(pp::Var(data)); | |
| 150 } | |
| 151 | |
| 152 // This object is the global object representing this plugin library as long | |
| 153 // as it is loaded. | |
| 154 class MyModule : public pp::Module { | |
| 155 public: | |
| 156 MyModule() : pp::Module() {} | |
| 157 virtual ~MyModule() {} | |
| 158 | |
| 159 // Override CreateInstance to create your customized Instance object. | |
| 160 virtual pp::Instance* CreateInstance(PP_Instance instance) { | |
| 161 return new MyInstance(instance); | |
| 162 } | |
| 163 }; | |
| 164 | |
| 165 namespace pp { | |
| 166 | |
| 167 // Factory function for your specialization of the Module object. | |
| 168 Module* CreateModule() { | |
| 169 return new MyModule(); | |
| 170 } | |
| 171 | |
| 172 } // namespace pp | |
| OLD | NEW |