Google APIs Client Library for C++
|
00001 /* 00002 * \copyright Copyright 2013 Google Inc. All Rights Reserved. 00003 * \license @{ 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 * 00017 * @} 00018 */ 00019 00020 // Author: ewiseblatt@google.com (Eric Wiseblatt) 00021 00022 #ifndef APISERVING_CLIENTSCPP_SERVICE_MEDIA_UPLOADER_H_ 00023 #define APISERVING_CLIENTSCPP_SERVICE_MEDIA_UPLOADER_H_ 00024 00025 #include <string> 00026 using std::string; 00027 #include "googleapis/client/transport/http_types.h" 00028 #include "googleapis/base/macros.h" 00029 #include "googleapis/base/callback.h" 00030 #include "googleapis/base/scoped_ptr.h" 00031 #include "googleapis/strings/stringpiece.h" 00032 #include "googleapis/util/status.h" 00033 namespace googleapis { 00034 00035 namespace client { 00036 class SerializableJson; 00037 class DataReader; 00038 class HttpRequest; 00039 00040 /* 00041 * Specifie the media upload interface for an endpoint. 00042 * @ingroup ClientServiceLayer 00043 * 00044 * The MediaUploadSpec captures the information in the discovery document 00045 * "MediaUpload/protocols" section for how to utilize a given protocol. 00046 * 00047 * The spec is given to a MediaUploader in order to configure it for the 00048 * current use case. 00049 * 00050 * This class only uses StringPiece for storage so that it can be used to 00051 * create instances as constant global or class variables. 00052 * 00053 * @see MediaUploader 00054 */ 00055 class MediaUploadSpec { 00056 public: 00057 /* 00058 * Constructs a default spec for hand-populating. 00059 */ 00060 MediaUploadSpec(); 00061 00062 /* 00063 * Standard constructor for this spec information. 00064 * 00065 00066 * @param[in] protocol Type type of media upload. 00067 * "simple", "resuanble", "dirct" 00068 * @param[in] path_template The default path template to use for the 00069 * upload if media upload were not actualy use. 00070 * @param[in] multipart True if multipart content types are supported. 00071 */ 00072 MediaUploadSpec( 00073 const StringPiece& protocol, 00074 const StringPiece& path_template, 00075 bool multipart); 00076 00077 /* 00078 * Standard destructor. 00079 */ 00080 virtual ~MediaUploadSpec(); 00081 00082 /* 00083 * Returns the path template for the specification. 00084 */ 00085 const StringPiece& path_template() const { return path_template_; } 00086 00087 /* 00088 * Changes template path. 00089 */ 00090 void set_path_template(const StringPiece& path_template) { 00091 path_template_ = path_template; 00092 } 00093 00094 /* 00095 * Returns a standard protocol name like "simple" or "resumable". 00096 */ 00097 const StringPiece& protocol() const { return protocol_; } 00098 00099 /* 00100 * Changes the protocol used by this specification instance. 00101 */ 00102 void set_protocol(const StringPiece& protocol) { protocol_ = protocol; } 00103 00104 /* 00105 * Determine if multipart forms are supported by this specification or not. 00106 * @return if can perform multipart uploads, false if not. 00107 */ 00108 bool is_multipart() const { return multipart_; } 00109 00110 /* 00111 * Use multipart upload. 00112 */ 00113 void set_multipart(bool multipart) { multipart_ = multipart; } 00114 00115 private: 00116 StringPiece protocol_; 00117 StringPiece path_template_; 00118 bool multipart_; 00119 00120 DISALLOW_COPY_AND_ASSIGN(MediaUploadSpec); 00121 }; 00122 00123 /* 00124 * Uploader for using Google media upload protocols. 00125 * @ingroup ClientServiceLayer 00126 * 00127 * In practice the methods generated by the code generator provide a factory 00128 * that creates one of these and you just populated it. The upload happens 00129 * when the method (acting as the factory) executes. 00130 * 00131 * <pre> 00132 * scoped_ptr<drive_api::File> file(drive_api::File::New()); 00133 * file->set_title(StrCat("Uploaded from ", path)); 00134 * 00135 * const DriveService::FilesResource& ops = app_->service()->get_files(); 00136 * scoped_ptr<FilesResource_InsertMethod> insert( 00137 * ops.NewInsertMethod(app_->credential())); 00138 * client::MediaUploader* uploader = insert->media_uploader(); 00139 * uploader->set_metadata(*file); 00140 * uploader->set_media_content(mime_type.as_string(), file_content); 00141 * insert->Execute(); 00142 * </pre> 00143 * 00144 * If using this yourself then instead of the insert->Execute you would call 00145 * uploader->upload, passing in the http_request to upload and http_response. 00146 * You can explicitly form the request yourself, or call BuildRequest to 00147 * initialize a standard one. 00148 * 00149 * The media uploader is not reusable at this time. 00150 * 00151 * TODO(ewiseblatt): Only a synchronous Upload is provided at this time 00152 * but eventually this will support asynchronous uploads. Even so, the 00153 * underlying HttpRequest and its HttpResponse attribute are threadsafe and 00154 * support condition variables so you can Upload in a thread and synchronize 00155 * on the response in another. 00156 * 00157 * TODO(ewiseblatt): The interface does not yet support 00158 * -- streaming content 00159 * -- resumable uploads 00160 *-- auto protocol selection 00161 * To add auto selection I'll probably configure it with a vector of specs to 00162 * choose from. 00163 */ 00164 class MediaUploader { 00165 public: 00166 /* 00167 * Callback function used to resolve URI templated variables in a URI 00168 * @param[in] StringPiece is the URI to resolve. 00169 * @param[out] The resolved URL 00170 * @return success if all the URI parameters could be resolved, failure 00171 * if somec could not. 00172 */ 00173 typedef ResultCallback2< util::Status, // Returns ok if fully prepared 00174 const StringPiece&, // URL to resolve 00175 string*> // resolved url 00176 UrlPreparer; 00177 00178 /* 00179 * Standard constructor 00180 * 00181 * @param[in] spec Should remain valid over the lifetime of the instance. 00182 * @param[in] base_url The url that the spec paths are relative to. 00183 * @param[in] non_media_upload_path The path to send metadata to when 00184 * there is no media content (i.e. the non-media upload case). 00185 * 00186 * TODO(ewiseblatt): In the future this will also be used if multipart is 00187 * not supported. 00188 */ 00189 explicit MediaUploader( 00190 const MediaUploadSpec* spec, 00191 const StringPiece& base_url, 00192 const StringPiece& non_media_upload_path); 00193 00194 /* 00195 * Standard destructor 00196 */ 00197 virtual ~MediaUploader(); 00198 00199 /* 00200 * Find out if BuildRequest was called and returned successfully 00201 * so that the uploader is ready to Upload(). 00202 * 00203 * @return true if can perform media upload, false if not yet ready. 00204 */ 00205 bool is_ready() const { return ready_; } 00206 00207 /* 00208 * Set custom multipart oundary separator. 00209 * 00210 * Overrides the boundary used for multipart separators should this instance 00211 * ever create a multipart content_type. 00212 * 00213 * If the boundary is empty then it will be automatically determined from 00214 * the content. Since the content reader may not be resettable, relying on 00215 * auto-boundaries might make the request unsendable if the content payload 00216 * cannot be reset between discovering the boundary and sending the message. 00217 */ 00218 void set_multipart_boundary(const string& boundary) { 00219 multipart_boundary_ = boundary; 00220 } 00221 00222 /* 00223 * Returns the separator string used to denote the multipart boundary. 00224 */ 00225 const string& multipart_boundary() const { return multipart_boundary_; } 00226 00227 /* 00228 * Set the metadata using a Json object or pre-encoded string. 00229 * 00230 * @param[in] from_json If this is empty then no metadata will be added 00231 * (i.e. just a media upload). Otherwise this is a JSON-encoded 00232 * metadata payload. 00233 */ 00234 void set_metadata(const SerializableJson& from_json); 00235 00236 /* 00237 * Set the metadata using a Json object or pre-encoded string. 00238 * @param[in] content_type The content type of the metadata payload. 00239 * @param[in] from_text The content_type encoded metadata payload. 00240 */ 00241 void set_metadata(const string& content_type, const string& from_text); 00242 00243 /* 00244 * Set the media content payload byte stream. 00245 * 00246 * @param[in] content_type The media payload content type. 00247 * @param[in] media Takes ownership of the mdeia payload byte stream. 00248 * 00249 * If the reader is known to be empty then no content will be uploaded 00250 * allowing the uploader to just send the metadata (if any). 00251 */ 00252 void set_media_content_reader(const string& content_type, DataReader* media); 00253 00254 /* 00255 * Returns the base_url bound in teh constructor. 00256 */ 00257 const string& base_url() const { return base_url_; } 00258 00259 /* 00260 * Returns the non_media_upload_path bound in the constructor. 00261 */ 00262 const string& non_media_upload_path() const { 00263 return non_media_upload_path_; 00264 } 00265 00266 /* 00267 * Synchronously perform the upload protocol using the given request. 00268 * 00269 * This method requires BuildRequest was called to fill out the request. 00270 * If authorization is needed, the credentials should be set on the request. 00271 * 00272 * @param[in,out] http_request The request used to perform the upload. 00273 * @return The overall status of the upload. Error detail can be retrieved 00274 * from the http_request->status(). 00275 * 00276 */ 00277 util::Status Upload(HttpRequest* http_request); 00278 00279 /* 00280 * prepares the uploader and builds the HttpRequest. 00281 * 00282 * This fills out the request body and any critical headers that the 00283 * underlying protocol uses. Any metadata and content attributes for 00284 * the uploader must be set before calling this method. 00285 * 00286 * This method also determines the final protocol and url endpoint to use. 00287 * The url_preparer is used to resolve variables in templated urls and add 00288 * any other query parameters. It is only called once so can be a single 00289 * use callback. It can be left NULL to not modify the protocol url, but 00290 * should only do so if there are known to be no templated parameters 00291 * in the urls or extra query parameters needed in the upload request. 00292 * 00293 * @param[in,out] request The request to build. 00294 * @param[in] url_preparer The Callback for resolving template variables 00295 * in the upload url if it was specified using URI Templating.. 00296 */ 00297 util::Status BuildRequest(HttpRequest* request, UrlPreparer* url_preparer); 00298 00299 private: 00300 const MediaUploadSpec* spec_; // bound in constructor 00301 string multipart_boundary_; // when generating multipart payloads 00302 string base_url_; 00303 string non_media_upload_path_; 00304 00305 // TODO(ewiseblatt): change this to a reader after adding reader to Json. 00306 string metadata_content_; 00307 string metadata_content_type_; 00308 00309 scoped_ptr<DataReader> media_content_reader_; 00310 string media_content_type_; 00311 00312 bool ready_; // Set true within BuildRequest 00313 00314 /* 00315 * Helper function for BuildPayload when payload is a multipart form. 00316 * @param[out] content_type The content type for the reader returned. 00317 * @return Reader containing the payload for the HTTP upload request. 00318 */ 00319 DataReader* CreateMultipartPayloadReader(string* content_type); 00320 00321 DISALLOW_COPY_AND_ASSIGN(MediaUploader); 00322 }; 00323 00324 } // namespace client 00325 00326 } // namespace googleapis 00327 #endif // APISERVING_CLIENTSCPP_SERVICE_MEDIA_UPLOADER_H_