tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

HTMLFormSubmission.h (9760B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_HTMLFormSubmission_h
      8 #define mozilla_dom_HTMLFormSubmission_h
      9 
     10 #include "mozilla/Encoding.h"
     11 #include "mozilla/dom/HTMLDialogElement.h"
     12 #include "mozilla/dom/UserActivation.h"
     13 #include "nsCOMPtr.h"
     14 #include "nsString.h"
     15 
     16 class nsIURI;
     17 class nsIInputStream;
     18 class nsGenericHTMLElement;
     19 class nsIMultiplexInputStream;
     20 
     21 namespace mozilla::dom {
     22 
     23 class Blob;
     24 class DialogFormSubmission;
     25 class Directory;
     26 class Element;
     27 class HTMLFormElement;
     28 
     29 /**
     30 * Class for form submissions; encompasses the function to call to submit as
     31 * well as the form submission name/value pairs
     32 */
     33 class HTMLFormSubmission {
     34 public:
     35  /**
     36   * Get a submission object based on attributes in the form (ENCTYPE and
     37   * METHOD)
     38   *
     39   * @param aForm the form to get a submission object based on
     40   * @param aSubmitter the submitter element (can be null)
     41   * @param aEncoding the submiter element's encoding
     42   * @param aFormSubmission the form submission object (out param)
     43   */
     44  static nsresult GetFromForm(HTMLFormElement* aForm,
     45                              nsGenericHTMLElement* aSubmitter,
     46                              NotNull<const Encoding*>& aEncoding,
     47                              FormData* aFormData,
     48                              HTMLFormSubmission** aFormSubmission);
     49 
     50  MOZ_COUNTED_DTOR_VIRTUAL(HTMLFormSubmission)
     51 
     52  /**
     53   * Submit a name/value pair
     54   *
     55   * @param aName the name of the parameter
     56   * @param aValue the value of the parameter
     57   */
     58  virtual nsresult AddNameValuePair(const nsAString& aName,
     59                                    const nsAString& aValue) = 0;
     60 
     61  /**
     62   * Submit a name/blob pair
     63   *
     64   * @param aName the name of the parameter
     65   * @param aBlob the blob to submit. The file's name will be used if the Blob
     66   * is actually a File, otherwise 'blob' string is used instead. Must not be
     67   * null.
     68   */
     69  virtual nsresult AddNameBlobPair(const nsAString& aName, Blob* aBlob) = 0;
     70 
     71  /**
     72   * Submit a name/directory pair
     73   *
     74   * @param aName the name of the parameter
     75   * @param aBlob the directory to submit.
     76   */
     77  virtual nsresult AddNameDirectoryPair(const nsAString& aName,
     78                                        Directory* aDirectory) = 0;
     79 
     80  /**
     81   * Given a URI and the current submission, create the final URI and data
     82   * stream that will be submitted.  Subclasses *must* implement this.
     83   *
     84   * @param aURI the URI being submitted to [IN]
     85   * @param aPostDataStream a data stream for POST data [OUT]
     86   * @param aOutURI the resulting URI. May be the same as aURI [OUT]
     87   */
     88  virtual nsresult GetEncodedSubmission(nsIURI* aURI,
     89                                        nsIInputStream** aPostDataStream,
     90                                        nsCOMPtr<nsIURI>& aOutURI) = 0;
     91 
     92  /**
     93   * Get the charset that will be used for submission.
     94   */
     95  void GetCharset(nsACString& aCharset) { mEncoding->Name(aCharset); }
     96 
     97  /**
     98   * Get the action URI that will be used for submission.
     99   */
    100  nsIURI* GetActionURL() const { return mActionURL; }
    101 
    102  /**
    103   * Get the target that will be used for submission.
    104   */
    105  void GetTarget(nsAString& aTarget) { aTarget = mTarget; }
    106 
    107  /**
    108   * Return true if this form submission was user-initiated.
    109   */
    110  bool IsInitiatedFromUserInput() const { return mInitiatedFromUserInput; }
    111 
    112  virtual DialogFormSubmission* GetAsDialogSubmission() { return nullptr; }
    113 
    114  FormData* GetFormData() const { return mFormData; }
    115 
    116 protected:
    117  /**
    118   * Can only be constructed by subclasses.
    119   *
    120   * @param aEncoding the character encoding of the form
    121   */
    122  HTMLFormSubmission(nsIURI* aActionURL, const nsAString& aTarget,
    123                     mozilla::NotNull<const mozilla::Encoding*> aEncoding);
    124 
    125  // The action url.
    126  nsCOMPtr<nsIURI> mActionURL;
    127 
    128  // The target.
    129  nsString mTarget;
    130 
    131  // The character encoding of this form submission
    132  mozilla::NotNull<const mozilla::Encoding*> mEncoding;
    133 
    134  RefPtr<FormData> mFormData;
    135 
    136  // Keep track of whether this form submission was user-initiated or not
    137  bool mInitiatedFromUserInput;
    138 };
    139 
    140 class EncodingFormSubmission : public HTMLFormSubmission {
    141 public:
    142  EncodingFormSubmission(nsIURI* aActionURL, const nsAString& aTarget,
    143                         mozilla::NotNull<const mozilla::Encoding*> aEncoding,
    144                         Element* aSubmitter);
    145 
    146  virtual ~EncodingFormSubmission();
    147 
    148  // Indicates the type of newline normalization and escaping to perform in
    149  // `EncodeVal`, in addition to encoding the string into bytes.
    150  enum EncodeType {
    151    // Normalizes newlines to CRLF and then escapes for use in
    152    // `Content-Disposition`. (Useful for `multipart/form-data` entry names.)
    153    eNameEncode,
    154    // Escapes for use in `Content-Disposition`. (Useful for
    155    // `multipart/form-data` filenames.)
    156    eFilenameEncode,
    157    // Normalizes newlines to CRLF.
    158    eValueEncode,
    159  };
    160 
    161  /**
    162   * Encode a Unicode string to bytes, additionally performing escapes or
    163   * normalizations.
    164   * @param aStr the string to encode
    165   * @param aOut the encoded string [OUT]
    166   * @param aEncodeType The type of escapes or normalizations to perform on the
    167   *                    encoded string.
    168   * @throws an error if UnicodeToNewBytes fails
    169   */
    170  nsresult EncodeVal(const nsAString& aStr, nsCString& aOut,
    171                     EncodeType aEncodeType);
    172 };
    173 
    174 class DialogFormSubmission final : public HTMLFormSubmission {
    175 public:
    176  DialogFormSubmission(nsAString& aResult, NotNull<const Encoding*> aEncoding,
    177                       HTMLDialogElement* aDialogElement)
    178      : HTMLFormSubmission(nullptr, u""_ns, aEncoding),
    179        mDialogElement(aDialogElement),
    180        mReturnValue(aResult) {}
    181  nsresult AddNameValuePair(const nsAString& aName,
    182                            const nsAString& aValue) override {
    183    MOZ_CRASH("This method should not be called");
    184    return NS_OK;
    185  }
    186 
    187  nsresult AddNameBlobPair(const nsAString& aName, Blob* aBlob) override {
    188    MOZ_CRASH("This method should not be called");
    189    return NS_OK;
    190  }
    191 
    192  nsresult AddNameDirectoryPair(const nsAString& aName,
    193                                Directory* aDirectory) override {
    194    MOZ_CRASH("This method should not be called");
    195    return NS_OK;
    196  }
    197 
    198  nsresult GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream,
    199                                nsCOMPtr<nsIURI>& aOutURI) override {
    200    MOZ_CRASH("This method should not be called");
    201    return NS_OK;
    202  }
    203 
    204  DialogFormSubmission* GetAsDialogSubmission() override { return this; }
    205 
    206  HTMLDialogElement* DialogElement() { return mDialogElement; }
    207 
    208  nsString& ReturnValue() { return mReturnValue; }
    209 
    210 private:
    211  const RefPtr<HTMLDialogElement> mDialogElement;
    212  nsString mReturnValue;
    213 };
    214 
    215 /**
    216 * Handle multipart/form-data encoding, which does files as well as normal
    217 * inputs.  This always does POST.
    218 */
    219 class FSMultipartFormData : public EncodingFormSubmission {
    220 public:
    221  /**
    222   * @param aEncoding the character encoding of the form
    223   */
    224  FSMultipartFormData(nsIURI* aActionURL, const nsAString& aTarget,
    225                      mozilla::NotNull<const mozilla::Encoding*> aEncoding,
    226                      Element* aSubmitter);
    227  ~FSMultipartFormData();
    228 
    229  virtual nsresult AddNameValuePair(const nsAString& aName,
    230                                    const nsAString& aValue) override;
    231 
    232  virtual nsresult AddNameBlobPair(const nsAString& aName,
    233                                   Blob* aBlob) override;
    234 
    235  virtual nsresult AddNameDirectoryPair(const nsAString& aName,
    236                                        Directory* aDirectory) override;
    237 
    238  virtual nsresult GetEncodedSubmission(nsIURI* aURI,
    239                                        nsIInputStream** aPostDataStream,
    240                                        nsCOMPtr<nsIURI>& aOutURI) override;
    241 
    242  void GetContentType(nsACString& aContentType) {
    243    aContentType = "multipart/form-data; boundary="_ns + mBoundary;
    244  }
    245 
    246  nsIInputStream* GetSubmissionBody(uint64_t* aContentLength);
    247 
    248 protected:
    249  /**
    250   * Roll up the data we have so far and add it to the multiplexed data stream.
    251   */
    252  nsresult AddPostDataStream();
    253 
    254 private:
    255  void AddDataChunk(const nsACString& aName, const nsACString& aFilename,
    256                    const nsACString& aContentType,
    257                    nsIInputStream* aInputStream, uint64_t aInputStreamSize);
    258  /**
    259   * The post data stream as it is so far.  This is a collection of smaller
    260   * chunks--string streams and file streams interleaved to make one big POST
    261   * stream.
    262   */
    263  nsCOMPtr<nsIMultiplexInputStream> mPostData;
    264 
    265  /**
    266   * The same stream, but as an nsIInputStream.
    267   * Raw pointers because it is just QI of mInputStream.
    268   */
    269  nsIInputStream* mPostDataStream;
    270 
    271  /**
    272   * The current string chunk.  When a file is hit, the string chunk gets
    273   * wrapped up into an input stream and put into mPostDataStream so that the
    274   * file input stream can then be appended and everything is in the right
    275   * order.  Then the string chunk gets appended to again as we process more
    276   * name/value pairs.
    277   */
    278  nsCString mPostDataChunk;
    279 
    280  /**
    281   * The boundary string to use after each "part" (the boundary that marks the
    282   * end of a value).  This is computed randomly and is different for each
    283   * submission.
    284   */
    285  nsCString mBoundary;
    286 
    287  /**
    288   * The total length in bytes of the streams that make up mPostDataStream
    289   */
    290  uint64_t mTotalLength;
    291 };
    292 
    293 }  // namespace mozilla::dom
    294 
    295 #endif /* mozilla_dom_HTMLFormSubmission_h */