1 //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef ProtocolParser_h__ 7 #define ProtocolParser_h__ 8 9 #include "HashStore.h" 10 #include "chromium/safebrowsing.pb.h" 11 12 namespace mozilla { 13 namespace safebrowsing { 14 15 /** 16 * Abstract base class for parsing update data in multiple formats. 17 */ 18 class ProtocolParser { 19 public: 20 struct ForwardedUpdate { 21 nsCString table; 22 nsCString url; 23 }; 24 25 ProtocolParser(); 26 virtual ~ProtocolParser(); 27 Status()28 nsresult Status() const { return mUpdateStatus; } 29 30 #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES GetRawTableUpdates()31 virtual nsCString GetRawTableUpdates() const { return mPending; } 32 #endif 33 34 virtual void SetCurrentTable(const nsACString& aTable) = 0; 35 SetRequestedTables(const nsTArray<nsCString> & aRequestTables)36 void SetRequestedTables(const nsTArray<nsCString>& aRequestTables) { 37 mRequestedTables = aRequestTables.Clone(); 38 } 39 40 nsresult Begin(const nsACString& aTable, 41 const nsTArray<nsCString>& aUpdateTables); 42 virtual nsresult AppendStream(const nsACString& aData) = 0; 43 UpdateWaitSec()44 uint32_t UpdateWaitSec() { return mUpdateWaitSec; } 45 46 // Notify that the inbound data is ready for parsing if progressive 47 // parsing is not supported, for example in V4. 48 virtual void End() = 0; 49 50 RefPtr<TableUpdate> GetTableUpdate(const nsACString& aTable); ForgetTableUpdates()51 void ForgetTableUpdates() { mTableUpdates.Clear(); } GetTableUpdates()52 const TableUpdateArray& GetTableUpdates() { return mTableUpdates; } 53 54 // These are only meaningful to V2. Since they were originally public, 55 // moving them to ProtocolParserV2 requires a dymamic cast in the call 56 // sites. As a result, we will leave them until we remove support 57 // for V2 entirely.. Forwards()58 virtual const nsTArray<ForwardedUpdate>& Forwards() const { 59 return mForwards; 60 } ResetRequested()61 bool ResetRequested() const { return !mTablesToReset.IsEmpty(); } TablesToReset()62 const nsTArray<nsCString>& TablesToReset() const { return mTablesToReset; } 63 64 protected: 65 virtual RefPtr<TableUpdate> CreateTableUpdate( 66 const nsACString& aTableName) const = 0; 67 68 nsCString mPending; 69 nsresult mUpdateStatus; 70 71 // Keep track of updates to apply before passing them to the DBServiceWorkers. 72 TableUpdateArray mTableUpdates; 73 74 nsTArray<ForwardedUpdate> mForwards; 75 76 // The table names that were requested from the client. 77 nsTArray<nsCString> mRequestedTables; 78 79 // The table names that failed to update and need to be reset. 80 nsTArray<nsCString> mTablesToReset; 81 82 // How long we should wait until the next update. 83 uint32_t mUpdateWaitSec; 84 }; 85 86 /** 87 * Helpers to parse the "shavar", "digest256" and "simple" list formats. 88 */ 89 class ProtocolParserV2 final : public ProtocolParser { 90 public: 91 ProtocolParserV2(); 92 virtual ~ProtocolParserV2(); 93 94 virtual void SetCurrentTable(const nsACString& aTable) override; 95 virtual nsresult AppendStream(const nsACString& aData) override; 96 virtual void End() override; 97 98 // Update information. Forwards()99 virtual const nsTArray<ForwardedUpdate>& Forwards() const override { 100 return mForwards; 101 } 102 103 #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES 104 // Unfortunately we have to override to return mRawUpdate which 105 // will not be modified during the parsing, unlike mPending. GetRawTableUpdates()106 virtual nsCString GetRawTableUpdates() const override { return mRawUpdate; } 107 #endif 108 109 private: 110 virtual RefPtr<TableUpdate> CreateTableUpdate( 111 const nsACString& aTableName) const override; 112 113 nsresult ProcessControl(bool* aDone); 114 nsresult ProcessExpirations(const nsCString& aLine); 115 nsresult ProcessChunkControl(const nsCString& aLine); 116 nsresult ProcessForward(const nsCString& aLine); 117 nsresult AddForward(const nsACString& aUrl); 118 nsresult ProcessChunk(bool* done); 119 // Remove this, it's only used for testing 120 nsresult ProcessPlaintextChunk(const nsACString& aChunk); 121 nsresult ProcessShaChunk(const nsACString& aChunk); 122 nsresult ProcessHostAdd(const Prefix& aDomain, uint8_t aNumEntries, 123 const nsACString& aChunk, uint32_t* aStart); 124 nsresult ProcessHostSub(const Prefix& aDomain, uint8_t aNumEntries, 125 const nsACString& aChunk, uint32_t* aStart); 126 nsresult ProcessHostAddComplete(uint8_t aNumEntries, const nsACString& aChunk, 127 uint32_t* aStart); 128 nsresult ProcessHostSubComplete(uint8_t numEntries, const nsACString& aChunk, 129 uint32_t* start); 130 // Digest chunks are very similar to shavar chunks, except digest chunks 131 // always contain the full hash, so there is no need for chunk data to 132 // contain prefix sizes. 133 nsresult ProcessDigestChunk(const nsACString& aChunk); 134 nsresult ProcessDigestAdd(const nsACString& aChunk); 135 nsresult ProcessDigestSub(const nsACString& aChunk); 136 bool NextLine(nsACString& aLine); 137 138 enum ParserState { PROTOCOL_STATE_CONTROL, PROTOCOL_STATE_CHUNK }; 139 ParserState mState; 140 141 enum ChunkType { 142 // Types for shavar tables. 143 CHUNK_ADD, 144 CHUNK_SUB, 145 // Types for digest256 tables. digest256 tables differ in format from 146 // shavar tables since they only contain complete hashes. 147 CHUNK_ADD_DIGEST, 148 CHUNK_SUB_DIGEST 149 }; 150 151 struct ChunkState { 152 ChunkType type; 153 uint32_t num; 154 uint32_t hashSize; 155 uint32_t length; ClearChunkState156 void Clear() { 157 num = 0; 158 hashSize = 0; 159 length = 0; 160 } 161 }; 162 ChunkState mChunkState; 163 164 // Updates to apply to the current table being parsed. 165 RefPtr<TableUpdateV2> mTableUpdate; 166 167 #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES 168 nsCString mRawUpdate; // Keep a copy of mPending before it's processed. 169 #endif 170 }; 171 172 // Helpers to parse the "proto" list format. 173 class ProtocolParserProtobuf final : public ProtocolParser { 174 public: 175 typedef FetchThreatListUpdatesResponse_ListUpdateResponse ListUpdateResponse; 176 typedef google::protobuf::RepeatedPtrField<ThreatEntrySet> ThreatEntrySetList; 177 178 public: 179 ProtocolParserProtobuf(); 180 181 virtual void SetCurrentTable(const nsACString& aTable) override; 182 virtual nsresult AppendStream(const nsACString& aData) override; 183 virtual void End() override; 184 185 private: 186 virtual ~ProtocolParserProtobuf(); 187 188 virtual RefPtr<TableUpdate> CreateTableUpdate( 189 const nsACString& aTableName) const override; 190 191 // For parsing update info. 192 nsresult ProcessOneResponse(const ListUpdateResponse& aResponse, 193 nsACString& aListName); 194 195 nsresult ProcessAdditionOrRemoval(TableUpdateV4& aTableUpdate, 196 const ThreatEntrySetList& aUpdate, 197 bool aIsAddition); 198 199 nsresult ProcessRawAddition(TableUpdateV4& aTableUpdate, 200 const ThreatEntrySet& aAddition); 201 202 nsresult ProcessRawRemoval(TableUpdateV4& aTableUpdate, 203 const ThreatEntrySet& aRemoval); 204 205 nsresult ProcessEncodedAddition(TableUpdateV4& aTableUpdate, 206 const ThreatEntrySet& aAddition); 207 208 nsresult ProcessEncodedRemoval(TableUpdateV4& aTableUpdate, 209 const ThreatEntrySet& aRemoval); 210 }; 211 212 } // namespace safebrowsing 213 } // namespace mozilla 214 215 #endif 216