Google APIs Client Library for C++
http_scribe.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 #ifndef APISERVING_CLIENTS_CPP_TRANSPORT_HTTP_SCRIBE_H_
00021 #define APISERVING_CLIENTS_CPP_TRANSPORT_HTTP_SCRIBE_H_
00022 
00023 #include <map>
00024 using std::map;
00025 #include <queue>
00026 using std::queue;
00027 #include <set>
00028 using std::multiset;
00029 using std::set;
00030 #include <string>
00031 using std::string;
00032 #include "googleapis/base/integral_types.h"
00033 #include "googleapis/base/macros.h"
00034 #include "googleapis/base/mutex.h"
00035 #include "googleapis/base/scoped_ptr.h"
00036 #include "googleapis/base/thread_annotations.h"
00037 #include "googleapis/strings/stringpiece.h"
00038 #include "googleapis/util/status.h"
00039 namespace googleapis {
00040 
00041 namespace client {
00042 class HttpRequest;
00043 class ParsedUrl;
00044 
00045 /*
00046  * Determines what is appropriate for scribes to record.
00047  * @ingroup TransportLayerCore
00048  *
00049  * The base class performs standard censoring
00050  *   - Authorization headers are scrubbed
00051  */
00052 class HttpScribeCensor {
00053  public:
00054   /*
00055    * Standard constructor.
00056    */
00057   HttpScribeCensor();
00058 
00059   /*
00060    * Standard destructor.
00061    */
00062   virtual ~HttpScribeCensor();
00063 
00064   /*
00065    * Returns a scribbed url for the request.
00066    */
00067   virtual string GetCensoredUrl(
00068       const HttpRequest& request, bool* censored) const;
00069 
00070   /*
00071    * Returns a scrubbed request payload.
00072    *
00073    * The method should reset request->content_reader after reading
00074    * the contents.
00075    *
00076    * @param[in] request The request to censor.
00077    * @param[in] max_len The maximum length of body to keep.
00078    * @param[out] original_size The original uncensored size.
00079    * @param[out] censored Set to true if the result was censored.
00080    *
00081    * @return The censored request payload.
00082    */
00083   // TODO(ewiseblatt): 20130520
00084   // Really this should return a DataReader of either the original
00085   // reader or censored content but ownership cases are tricky and is
00086   // more vulnerable to rewind bugs so am leaving this as a string for now.
00087   virtual string GetCensoredRequestContent(
00088       const HttpRequest& request,
00089       int64 max_len,
00090       int64* original_size,
00091       bool* censored) const;
00092 
00093   /*
00094    * Returns a scrubbed responze payload.
00095    *
00096    * The method should reset response->body_reader after reading the contents.
00097    *
00098    * @param[in] request The request with the response to censor.
00099    * @param[in] max_len  The maximum length of body to keep.
00100    * @param[out] original_size The original uncensored size.
00101    * @param[out] censored Set to true if the result was censored.
00102    *
00103    * @return The censored response payload.
00104    */
00105   // TODO(ewiseblatt): 20130520
00106   // Really this should return a DataReader of either the original
00107   // reader or censored content but ownership cases are tricky and is
00108   // more vulnerable to rewind bugs so am leaving this as a string for now.
00109   virtual string GetCensoredResponseBody(
00110       const HttpRequest& request, int64 max_len,
00111       int64* original_size, bool* censored) const;
00112 
00113   /*
00114    * Returns a censored request header value.
00115    *
00116    * @param[in] request The request with the header.
00117    * @param[in] name The request header name.
00118    * @param[in] value The original value.
00119    * @param[out] censored True if the value was censored.
00120    *
00121    * @return The censored header value.
00122    */
00123   virtual string GetCensoredRequestHeaderValue(
00124       const HttpRequest& request,
00125       const StringPiece& name, const StringPiece& value,
00126       bool* censored) const;
00127 
00128   /*
00129    * Returns a censored response header value.
00130    *
00131    * @param[in] request The request with response having the header.
00132    * @param[in] name The response header name.
00133    * @param[in] value The original value.
00134    * @param[out] censored True if the value was censored.
00135    *
00136    * @return The censored header value.
00137    */
00138   virtual string GetCensoredResponseHeaderValue(
00139       const HttpRequest& request,
00140       const StringPiece& name, const StringPiece& value,
00141       bool* censored) const;
00142 
00143   /*
00144    * Returns the set of censored URL prefixes.
00145    *
00146    * These include the protocol (e.g. https://accounts.google.com)
00147    */
00148   const set<string>& censored_url_prefixes() const {
00149     return censored_url_prefixes_;
00150   }
00151 
00152   /*
00153    * Returns a mutable set of censored URL prefixes.
00154    *
00155    * These include the protocol (e.g. https://accounts.google.com).
00156    * You can add additional prefixes into the set.
00157    */
00158   set<string>* mutable_censored_url_prefixes() {
00159     return &censored_url_prefixes_;
00160   }
00161 
00162   /*
00163    * Returns a set of censored query parameter names.
00164    */
00165   const set<string>& censored_query_param_names() const {
00166     return censored_query_param_names_;
00167   }
00168 
00169   /*
00170    * Returns a mutable set of censored URL query parameters.
00171    *
00172    * You can add additional query parameter names into the set.
00173    */
00174   set<string>* mutable_censored_query_param_names() {
00175     return &censored_query_param_names_;
00176   }
00177 
00178   /*
00179    * Returns a set of censored HTTP request header names.
00180    */
00181   const set<string>& censored_request_header_names() const {
00182     return censored_request_header_names_;
00183   }
00184 
00185   /*
00186    * Returns a mutable set of censored HTTP request header names.
00187    *
00188    * You can add additional request header names into the set.
00189    */
00190   set<string>* mutable_censored_request_header_names() {
00191     return &censored_request_header_names_;
00192   }
00193 
00194   /*
00195    * Returns a set of censored HTTP response header names.
00196    */
00197   const set<string>& censored_response_header_names() const {
00198     return censored_response_header_names_;
00199   }
00200 
00201   /*
00202    * Returns a mutable set of censored HTTP reponse header names.
00203    *
00204    * You can add additional response header names into the set.
00205    */
00206   set<string>* mutable_censored_response_header_names() {
00207     return &censored_response_header_names_;
00208   }
00209 
00210  protected:
00211   /*
00212    * Censor the query part of a URL.
00213    *
00214    * @param[in] parsed_url The parsed url to extract from.
00215    * @param[out] censored Set to true if some values were censored.
00216    * @return censored query string.
00217    */
00218   string GetCensoredUrlQuery(
00219       const ParsedUrl& parsed_url, bool* censored) const;
00220 
00221  private:
00222   set<string> censored_url_prefixes_;
00223   set<string> censored_query_param_names_;
00224   set<string> censored_request_header_names_;
00225   set<string> censored_response_header_names_;
00226 
00227   bool IsSensitiveContent(const string& url) const;
00228   DISALLOW_COPY_AND_ASSIGN(HttpScribeCensor);
00229 };
00230 
00231 /*
00232  * Base class for scribe to log HTTP message activity.
00233  * @ingroup TransportLayerCore
00234  *
00235  * This is intended for debugging and diagnostics. A transport permits
00236  * binding a scribe to it to monitor transport activity. This class
00237  * provides the interface for the interaction between the HTTP requests
00238  * and scribes.
00239  *
00240  * Scribes should be thread-safe.
00241  *
00242  * @see HttpTransport::set_scribe
00243  */
00244 class HttpScribe {
00245  public:
00246   /*
00247    * Standard destructor.
00248    */
00249   virtual ~HttpScribe();
00250 
00251   /*
00252    * Specifies the max size for captured content snippets.
00253    *
00254    * The default is unbounded so the whole message will be kept.
00255    * If you only need part of the payload then you can use this attribute
00256    * to restrict the size.
00257    *
00258    * @param[in] n most bytes to capture.
00259    */
00260   void set_max_snippet(int64 n)  { max_snippet_ = n; }
00261 
00262   /*
00263    * Returns the max size for captured snippets.
00264    *
00265    * @return bytes to capture.
00266    */
00267   int64 max_snippet() const  { return max_snippet_; }
00268 
00269   /*
00270    * Notification that the request is about to be sent to the transport.
00271    *
00272    * Since the scribe is used in the flow of normal sending activities,
00273    * it will be the caller's responsibility to reset the requset->body_reader.
00274    * after invoking this method.
00275    *
00276    * @param[in] request The request being sent.
00277    */
00278   virtual void AboutToSendRequest(const HttpRequest* request) = 0;
00279 
00280   /*
00281    * Notification that a request has received a response.
00282    *
00283    * Since the scribe is used in the flow of normal sending activities,
00284    * it will be the caller's responsibility to reset the
00285    * request->response->body_reader after invoking this method.
00286    *
00287    * @param[in] request The request holds its response.
00288    */
00289   virtual void ReceivedResponseForRequest(const HttpRequest* request) = 0;
00290 
00291   /*
00292    * Notification that a sent request has encountered a transport error.
00293    *
00294    * Transport errors are not HTTP errors. This is a timeout or network-level
00295    * error.
00296    *
00297    * @param[in] request The request that will never receive a response.
00298    * @param[in] error The transport error.
00299    */
00300   virtual void RequestFailedWithTransportError(
00301       const HttpRequest* request, const util::Status& error) = 0;
00302 
00303   void reset_censor(HttpScribeCensor* censor) {
00304     censor_.reset(censor);
00305   }
00306 
00307   const HttpScribeCensor* censor() { return censor_.get(); }
00308 
00309   /*
00310    * Checkpoint the scribe data into the writer if it
00311    * hasnt been done so already.
00312    */
00313   virtual void Checkpoint() = 0;
00314 
00315  protected:
00316   /*
00317    * Class is abstract so needs to be specialized to construct.
00318    *
00319    * @param[in] censor Provides policy for censoring data. Ownership is passed.
00320    */
00321   explicit HttpScribe(HttpScribeCensor* censor);
00322 
00323  private:
00324   scoped_ptr<HttpScribeCensor> censor_;
00325   int64 max_snippet_;
00326   DISALLOW_COPY_AND_ASSIGN(HttpScribe);
00327 };
00328 
00329 /*
00330  * A high level but still abstract class for intercepting HTTP requests.
00331  * @ingroup TransportLayerCore
00332  *
00333  * This class manages a collection of active HttpEntryScribe::Entry
00334  * instances with activity associated with them. This might be a more useful
00335  * starting point for viewing a collection of independent encapsulated
00336  * messages as opposed to a stream of interleaved events.
00337  */
00338 class HttpEntryScribe : public HttpScribe {
00339  public:
00340   class Entry {
00341    public:
00342     /*
00343      * Standard constructor.
00344      *
00345      * @param[in] scribe The scribe constructing the entry.
00346      * @param[in] request The request that the entry is for.
00347      *
00348      * Caller should call either CancelAndDestroy or FlushAndDestroy when done.
00349      */
00350     Entry(HttpEntryScribe* scribe, const HttpRequest* request);
00351 
00352     /*
00353      * Finish recording the entry instance and destroy it.
00354      *
00355      * The entry has finished so should finish recording. Ownershp is passed
00356      * so that it can be destroyed. The entry is no longer in the scribe's
00357      * map or queue.
00358      *
00359      * This is called from the scribe within a critical section so does
00360      * not have to worry about threads.
00361      */
00362     virtual void FlushAndDestroy() = 0;
00363 
00364     /*
00365      * Destroys instance without flushing it so may forget about it.
00366      *
00367      * Intended to destory an instance without recording it.
00368      */
00369     virtual void CancelAndDestroy();
00370 
00371     /*
00372      * Hook for recording that the request was sent.
00373      *
00374      * @param[in] request The request is about to be executed.
00375      */
00376     virtual void Sent(const HttpRequest* request) = 0;
00377 
00378     /*
00379      * Hook for recording that the request received a response.
00380      *
00381      * @param[in] request The request has a response. The response
00382      * might be an HTTP failure.
00383      */
00384     virtual void Received(const HttpRequest* request) = 0;
00385 
00386     /*
00387      * Hook for recording that the request encountered a transport error.
00388      *
00389      * @param[in] request The request encountered a transport error so will
00390      *            never receive a response. It might have been previously sent
00391      *            but might not have.
00392      * @param[in] status Explains te error.
00393      */
00394     virtual void Failed(
00395         const HttpRequest* request, const util::Status& status) = 0;
00396 
00397     /*
00398      * Returns the age of this intance.
00399      *
00400      * @return microseconds since constructed.
00401      */
00402     int64 MicrosElapsed() const;
00403 
00404     /*
00405      * Returns bound scribe.
00406      *
00407      * @return scribe bound in constructor.
00408      */
00409     HttpEntryScribe* scribe() const { return scribe_; }
00410 
00411     /*
00412      * Returns bound request.
00413      *
00414      * @return request bound in constructor.
00415      */
00416     const HttpRequest* request() const  { return request_; }
00417 
00418     /*
00419      * Returns time instance was constructed.
00420      */
00421     const struct timeval& timeval() const  { return timeval_; }
00422 
00423     /*
00424      * Returns true if the request has completed.
00425      * If this is true then the request might have been destroyed already.
00426      *
00427      * The request will always be valid in the Sent, Received, and Failed
00428      * methods.
00429      *
00430      * @return true If the request is known to have finished.
00431      */
00432     bool done() const  { return done_; }
00433 
00434     /*
00435      * Informs the entry that the reqeust has finished.
00436      *
00437      * This method is called internally so you do not need to call this..
00438      */
00439     void set_done(bool is_done) { done_ = is_done; }
00440 
00441    protected:
00442     /*
00443      * Do not explicitly call this destructor.
00444      *
00445      * @see FlushAndDestroy
00446      * @see CancelAndDestroy
00447      */
00448     virtual ~Entry();  // Called by FlushAndDestroy or CancelAndDestroy
00449 
00450    private:
00451     HttpEntryScribe* scribe_;
00452     const HttpRequest* request_;
00453     struct timeval timeval_;
00454     bool done_;
00455 
00456     DISALLOW_COPY_AND_ASSIGN(Entry);
00457   };
00458 
00459   /*
00460    * Implements the HttpScribe::AboutToSendRequest method.
00461    *
00462    * This maps the request to an entry and calls the Entry::Sent method.
00463    *
00464    * @param[in] request The request that was sent.
00465    */
00466   virtual void AboutToSendRequest(const HttpRequest* request);
00467 
00468   /*
00469    * Implements the HttpScribe::ReceivedResponseForRequest method.
00470    *
00471    * This maps the request to an entry and calls the
00472    * Entry::Received method.
00473    *
00474    * @param[in] request The request whose response was received.
00475    */
00476   virtual void ReceivedResponseForRequest(const HttpRequest* request);
00477 
00478   /*
00479    * Implements the HttpScribe::RequestFailedWithTransportError method.
00480    *
00481    * This maps the request to an entry and calls the
00482    * Entry::Failed method.
00483    *
00484    * @param[in] request The request that had a transport failure.
00485    * @param[in] error An explanation of the failure.
00486    */
00487   virtual void RequestFailedWithTransportError(
00488       const HttpRequest* request, const util::Status& error);
00489 
00490  protected:
00491   /*
00492    * Standard constructor.
00493    *
00494    * @param[in] censor Ownership to the censorship policy is passed.
00495    */
00496   explicit HttpEntryScribe(HttpScribeCensor* censor);
00497 
00498   /*
00499    * Standard destructor.
00500    */
00501   virtual ~HttpEntryScribe();
00502 
00503   /*
00504    * Maps the request into a logical entry.
00505    *
00506    * @param[in] request The intercepted request.
00507    * @return the scribe maintains ownership for the entry consolidating
00508    *         activity for the request
00509    *
00510    * @see NewEntry
00511    * @see DiscardEntry
00512    */
00513   Entry* GetEntry(const HttpRequest* request) LOCKS_EXCLUDED(mutex_);
00514 
00515   /*
00516    * Unmaps and destroys the logical entry.
00517    *
00518    * This can be called to forget about the entry, but is normally handled
00519    * automatically by this scribe instance.
00520    *
00521    * @param[in,out] entry The entry will be destroyed.
00522    */
00523   void DiscardEntry(Entry* entry) LOCKS_EXCLUDED(mutex_);
00524 
00525   /*
00526    * Discard all the entries in the queue.
00527    *
00528    * Discarding the entries notifies the entry that it is done so it can
00529    * flush and remove itself. This method is here so that derived
00530    * destructors can call it if they need to finish the entry before
00531    * they destruct.
00532    *
00533    * The base class will call this to discard anything remaining in its
00534    * destructor.
00535    */
00536   void DiscardQueue();
00537 
00538   /*
00539    * Create a new entry instance for the request.
00540    *
00541    * This is called from within a critical section so does not have to
00542    * worry about threads.
00543    *
00544    * This lets specialized scribes return specialized entries that
00545    * drive the particular specialized behavior. It is called by
00546    * GetEntry.
00547    *
00548    * @return ownership of the entry.
00549    */
00550   virtual Entry* NewEntry(const HttpRequest* request)
00551       EXCLUSIVE_LOCKS_REQUIRED(mutex_)
00552       = 0;
00553 
00554   /*
00555    * Returns the entries that have not yet been unmapped.
00556    *
00557    * These are in the order they were created, which is probably
00558    * the order in which they were sent (minus race conditions).
00559    */
00560   queue<Entry*>* outstanding_queue() { return &queue_; }
00561 
00562  private:
00563   typedef map<const HttpRequest*, Entry*> EntryMap;
00564   typedef queue<Entry*> EntryQueue;
00565 
00566   void UnsafeDiscardEntry(Entry* entry) EXCLUSIVE_LOCKS_REQUIRED(mutex_);
00567 
00568   Mutex mutex_;
00569   int64 sequence_number_ GUARDED_BY(mutex_);
00570   EntryMap map_ GUARDED_BY(mutex_);
00571   EntryQueue queue_ GUARDED_BY(mutex_);
00572 
00573   DISALLOW_COPY_AND_ASSIGN(HttpEntryScribe);
00574 };
00575 
00576 }  // namespace client
00577 
00578 } // namespace googleapis
00579 #endif  // APISERVING_CLIENTS_CPP_TRANSPORT_HTTP_SCRIBE_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines