Google APIs Client Library for C++
media_uploader.h
Go to the documentation of this file.
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_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines