diff --git a/lib/hive/base_error.rb b/lib/hive/base_error.rb
index 604280210827e6708e9ca94ec401763b4dcb5482..326a752129869e14229e7f1fcd62b797038a1e2d 100644
--- a/lib/hive/base_error.rb
+++ b/lib/hive/base_error.rb
@@ -74,6 +74,10 @@ module Hive
         raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
       end
       
+      if error.message.include? 'Invalid parameter'
+        raise Hive::ArgumentError, "#{context}: #{error.message}", build_backtrace(error)
+      end
+      
       if error.message.include? 'blk->transactions.size() > itr->trx_in_block'
         raise Hive::VirtualOperationsNotAllowedError, "#{context}: #{error.message}", build_backtrace(error)
       end
@@ -122,6 +126,10 @@ module Hive
         raise Hive::UpstreamResponseError, "#{context}: #{error.message}", build_backtrace(error)
       end
       
+      if error.message.include? 'Request Timeout'
+        raise Hive::RequestTimeoutUpstreamResponseError, "#{context}: #{error.message}", build_backtrace(error)
+      end
+      
       if error.message.include? 'Bad or missing upstream response'
         raise Hive::BadOrMissingUpstreamResponseError, "#{context}: #{error.message}", build_backtrace(error)
       end
@@ -205,6 +213,7 @@ module Hive
   class UpstreamResponseError < RemoteNodeError; end
   class RemoteDatabaseLockError < UpstreamResponseError; end
   class PluginNotEnabledError < UpstreamResponseError; end
+  class RequestTimeoutUpstreamResponseError < UpstreamResponseError; end
   class BadOrMissingUpstreamResponseError < UpstreamResponseError; end
   class TransactionIndexDisabledError < BaseError; end
   class NotAppBaseError < BaseError; end
diff --git a/lib/hive/fallback.rb b/lib/hive/fallback.rb
index e17ff11cf32239e26fd19fce0bdceab2cdc37965..dc28e94b0e278cb9f21e468c91cdadc218c05716 100644
--- a/lib/hive/fallback.rb
+++ b/lib/hive/fallback.rb
@@ -208,11 +208,25 @@ module Hive::Fallback
       :get_account_reputations
     ],
     bridge: [
+      :normalize_post,
+      :get_post_header,
+      :get_discussion,
+      :get_post,
+      :get_account_posts,
+      :get_ranked_posts,
+      :get_profile,
+      :get_trending_topics,
+      :post_notifications,
       :account_notifications,
+      :unread_notifications,
+      :get_payout_stats,
       :get_community,
-      :get_ranked_posts,
+      :get_community_context,
+      :list_pop_communities,
+      :list_subscribers,
       :list_all_subscriptions,
       :list_community_roles,
+      :list_communities
     ]
   }
   
@@ -277,11 +291,25 @@ module Hive::Fallback
       get_account_reputations: {account_lower_bound: String, limit: Integer}
     },
     bridge: {
-      account_notifications: {account: String, limit: Integer},
+      normalize_post: {post: Hash},
+      get_post_header: {author: String, permlink: String},
+      get_discussion: {author: String, permlink: String},
+      get_post: {author: String, permlink: String, observer: String},
+      get_account_posts: {sort: String, account: String, start_account: String, start_permlink: String, limit: Integer, observer: String},
+      get_ranked_posts: {sort: String, tag: String, observer: String, limit: Integer, start_author: String, start_permlink: String},
+      get_profile: {account: String, observer: String},
+      get_trending_topics: {limit: Integer, observer: String},
+      post_notifications: {author: String, permlink: String, min_score: Integer, last_id: String, limit: Integer},
+      account_notifications: {account: String, min_score: Integer, last_id: Integer, limit: Integer},
+      unread_notifications: {account: String, min_score: Integer},
+      get_payout_stats: {limit: Integer},
       get_community: {name: String, observer: String},
-      get_ranked_posts: {sort: String, tag: String, observer: String, limit: Integer},
-      list_all_subscriptions: {account: String},
-      list_community_roles: {community: String}
+      get_community_context: {name: String, account: String},
+      list_communities: {last: String, limit: Integer, query: String, sort: String, observer: String},
+      list_pop_communities: {limit: Integer},
+      list_community_roles: {community: String, last: String, limit: Integer},
+      list_subscribers: {community: String},
+      list_all_subscriptions: {account: String}
     }
   }
 end
diff --git a/lib/hive/rpc/http_client.rb b/lib/hive/rpc/http_client.rb
index e875adc26be556262a750317ea2b6a01f986af6a..bfdc85496abe8b153006995b0feedf9f3cddb671 100644
--- a/lib/hive/rpc/http_client.rb
+++ b/lib/hive/rpc/http_client.rb
@@ -17,7 +17,8 @@ module Hive
       # 
       # @private
       TIMEOUT_ERRORS = [Net::OpenTimeout, JSON::ParserError, Net::ReadTimeout,
-        Errno::EBADF, IOError, Errno::ENETDOWN, Hive::RemoteDatabaseLockError]
+        Errno::EBADF, IOError, Errno::ENETDOWN, Hive::RemoteDatabaseLockError,
+        Hive::RequestTimeoutUpstreamResponseError, Hive::RemoteNodeError]
       
       # @private
       POST_HEADERS = {
@@ -57,8 +58,10 @@ module Hive
       def rpc_execute(api_name = @api_name, api_method = nil, options = {}, &block)
         reset_timeout
         
-        catch :tota_cera_pila do; begin
-          request = http_post
+        response = nil
+        
+        loop do
+          request = http_post(api_name)
           
           request_object = if !!api_name && !!api_method
             put(api_name, api_method, options)
@@ -80,11 +83,11 @@ module Hive
           
           response = catch :http_request do; begin; http_request(request)
           rescue *TIMEOUT_ERRORS => e
-            throw retry_timeout(:http_request, e)
+            retry_timeout(:http_request, e) and redo
           end; end
           
           if response.nil?
-            throw retry_timeout(:tota_cera_pila, 'response was nil')
+            retry_timeout(:tota_cera_pila, 'response was nil') and redo
           end
           
           case response.code
@@ -108,6 +111,9 @@ module Hive
             else; response
             end
             
+            timeout_detected = false
+            timeout_cause = nil
+            
             [response].flatten.each_with_index do |r, i|
               if defined?(r.error) && !!r.error
                 if !!r.error.message
@@ -116,7 +122,10 @@ module Hive
                     rpc_args = [request_object].flatten[i]
                     raise_error_response rpc_method_name, rpc_args, r
                   rescue *TIMEOUT_ERRORS => e
-                    throw retry_timeout(:tota_cera_pila, e)
+                    timeout_detected = true
+                    timeout_cause = nil
+                    
+                    break # fail fast
                   end
                 else
                   raise Hive::ArgumentError, r.error.inspect
@@ -124,19 +133,29 @@ module Hive
               end
             end
             
+            if timeout_detected
+              retry_timeout(:tota_cera_pila, timeout_cause) and redo
+            end
+            
             yield_response response, &block
           when '504' # Gateway Timeout
-            throw retry_timeout(:tota_cera_pila, response.body)
+            retry_timeout(:tota_cera_pila, response.body) and redo
           when '502' # Bad Gateway
-            throw retry_timeout(:tota_cera_pila, response.body)
+            retry_timeout(:tota_cera_pila, response.body) and redo
           else
             raise UnknownError, "#{api_name}.#{api_method}: #{response.body}"
           end
-        end; end
+          
+          break # success!
+        end
+        
+        response
       end
       
       def rpc_batch_execute(options = {}, &block)
-        yield_response rpc_execute(nil, nil, options), &block
+        api_name = options[:api_name]
+        
+        yield_response rpc_execute(api_name, nil, options), &block
       end
     end
   end
diff --git a/lib/hive/rpc/thread_safe_http_client.rb b/lib/hive/rpc/thread_safe_http_client.rb
index 789fb2c53e91ce785bf8b5854de10dd7ed754f3a..3f0f0dcb8b8f509c2b4c27212d3e13269c4fd212 100644
--- a/lib/hive/rpc/thread_safe_http_client.rb
+++ b/lib/hive/rpc/thread_safe_http_client.rb
@@ -10,13 +10,20 @@ module Hive
     class ThreadSafeHttpClient < HttpClient
       SEMAPHORE = Mutex.new.freeze
       
-      # Same as #{HttpClient#http_post}, but scoped to each thread so it is
-      # thread safe.
-      def http_post
+      # Same as #{HttpClient#http_post}, but scoped to each thread, uri, and
+      # api_name so it is thread safe.
+      def http_post(api_name)
+        raise "Namespace required." if api_name.nil?
+        
         thread = Thread.current
-        http_post = thread.thread_variable_get(:http_post)
-        http_post ||= Net::HTTP::Post.new(uri.request_uri, POST_HEADERS)
-        thread.thread_variable_set(:http_post, http_post)
+        http_posts = thread.thread_variable_get(:http_posts) || {}
+        
+        SEMAPHORE.synchronize do
+          http_posts[[uri, api_name]] ||= Net::HTTP::Post.new(uri.request_uri, POST_HEADERS)
+          thread.thread_variable_set(:http_posts, http_posts)
+        end
+        
+        http_posts[[uri, api_name]]
       end
       
       def http_request(request); SEMAPHORE.synchronize{super}; end
diff --git a/test/hive/bridge_test.rb b/test/hive/bridge_test.rb
index d5b30bf86246f906fa615cc0adb4287ba972362c..d0d1f2036cb54514209d426d0413a2cbb2641021 100644
--- a/test/hive/bridge_test.rb
+++ b/test/hive/bridge_test.rb
@@ -4,6 +4,7 @@ module Hive
   class BridgeTest < Hive::Test
     def setup
       @api = Hive::Bridge.new(url: TEST_NODE)
+      @condenser_api = Hive::CondenserApi.new(url: TEST_NODE)
       @jsonrpc = Jsonrpc.new(url: TEST_NODE)
       @methods = @jsonrpc.get_api_methods[@api.class.api_name] rescue Fallback::API_METHODS[:bridge]
     end
@@ -13,7 +14,7 @@ module Hive
     end
     
     def test_inspect
-      assert_equal "#<Bridge [@chain=hive, @methods=<5 elements>]>", @api.inspect
+      assert_equal "#<Bridge [@chain=hive, @methods=<19 elements>]>", @api.inspect
     end
     
     def test_method_missing
@@ -28,6 +29,47 @@ module Hive
       end
     end
     
+    def test_normalize_post
+      vcr_cassette('bridge_normalize_post', record: :once) do
+        author = 'inertia'
+        permlink = 'kinda-spooky'
+        post = @condenser_api.get_content(author, permlink).result
+        options = {
+          post: post
+        }
+        
+        @api.normalize_post(options) do |result|
+          assert_equal Hashie::Mash, result.class
+          assert_equal author, result.author
+          assert_equal permlink, result.permlink
+          
+          known_normalization_fields = %w(post_id updated is_paidout payout_at payout
+            author_payout_value stats)
+            
+          assert_equal known_normalization_fields, result.keys - post.keys, 'found unknown fields added by hivemind normalization'
+        end
+      end
+    end
+    
+    def test_get_post_header
+      vcr_cassette('bridge_get_post_header', record: :once) do
+        author = 'inertia'
+        permlink = 'kinda-spooky'
+        post = @condenser_api.get_content(author, permlink).result
+        options = {
+          author: author,
+          permlink: permlink
+        }
+        
+        @api.get_post_header(options) do |result|
+          assert_equal Hashie::Mash, result.class
+          assert_equal author, result.author
+          assert_equal permlink, result.permlink
+          assert_equal [], result.keys - post.keys
+        end
+      end
+    end
+    
     def test_account_notifications
       vcr_cassette('bridge_account_notifications', record: :once) do
         options = {
@@ -54,12 +96,57 @@ module Hive
       end
     end
     
+    def test_get_discussion
+      vcr_cassette('bridge_get_discussion', record: :once) do
+        options = {
+          author: 'inertia',
+          permlink: 'kinda-spooky'
+        }
+        
+        @api.get_discussion(options) do |result|
+          assert_equal Hashie::Mash, result.class
+        end
+      end
+    end
+    
+    def test_get_post
+      vcr_cassette('bridge_get_post', record: :once) do
+        options = {
+          author: 'inertia',
+          permlink: 'kinda-spooky',
+          observer: 'alice'
+        }
+        
+        @api.get_post(options) do |result|
+          assert_equal Hashie::Mash, result.class
+        end
+      end
+    end
+    
+    def test_get_account_posts
+      vcr_cassette('bridge_get_account_posts', record: :once) do
+        options = {
+          sort: 'blog',
+          account: 'alice',
+          start_author: '',
+          start_permlink: '',
+          limit: 1,
+          observer: 'alice'
+        }
+        
+        @api.get_account_posts(options) do |result|
+          assert_equal Hashie::Array, result.class
+        end
+      end
+    end
+    
     def test_get_ranked_posts
       vcr_cassette('bridge_get_ranked_posts', record: :once) do
         options = {
           sort: 'trending',
           tag: '',
-          observer: 'alice'
+          observer: 'alice',
+          limit: 1
         }
         
         @api.get_ranked_posts(options) do |result|
@@ -68,6 +155,92 @@ module Hive
       end
     end
     
+    def test_get_profile
+      vcr_cassette('bridge_get_profile', record: :once) do
+        options = {
+          account: 'bob',
+          observer: 'alice'
+        }
+        
+        @api.get_profile(options) do |result|
+          assert_equal Hashie::Mash, result.class
+        end
+      end
+    end
+    
+    def test_get_trending_topics
+      vcr_cassette('bridge_get_trending_topics', record: :once) do
+        limit = 25
+        options = {
+          limit: limit,
+          observer: 'alice'
+        }
+        
+        @api.get_trending_topics(options) do |result|
+          assert_equal Hashie::Array, result.class
+          assert_equal limit, result.size
+        end
+      end
+    end
+    
+    def test_get_trending_topics_over_limit
+      vcr_cassette('bridge_get_trending_topics_over_limit', record: :once) do
+        limit = 26
+        options = {
+          limit: limit,
+          observer: 'alice'
+        }
+        
+        assert_raises Hive::ArgumentError do
+          @api.get_trending_topics(options)
+        end
+      end
+    end
+    
+    def test_post_notifications_empty
+      vcr_cassette('bridge_post_notifications', record: :once) do
+        limit = 0
+        options = {
+          author: '',
+          permlink: '',
+          last_id: '',
+          min_score: 25,
+          limit: limit
+        }
+        
+        assert_raises Hive::ArgumentError do
+          @api.post_notifications(options)
+        end
+      end
+    end
+    
+    def test_unread_notifications
+      vcr_cassette('bridge_unread_notifications', record: :once) do
+        options = {
+          account: 'alice',
+          min_score: 25
+        }
+        
+        @api.unread_notifications(options) do |result|
+          assert_equal Hashie::Mash, result.class
+        end
+      end
+    end
+    
+    def test_get_payout_stats
+      vcr_cassette('bridge_get_payout_stats', record: :once) do
+        limit = 250
+        options = {
+          limit: limit
+        }
+        
+        @api.get_payout_stats(options) do |result|
+          assert_equal Hashie::Mash, result.class
+          assert_equal limit, result.items.size
+        end
+      end
+    end
+    
     def test_list_all_subscriptions
       vcr_cassette('bridge_list_all_subscriptions', record: :once) do
         options = {
@@ -91,5 +264,73 @@ module Hive
         end
       end
     end
+    
+    def test_list_communities_empty
+      vcr_cassette('bridge_list_communities_empty', record: :once) do
+        options = {
+          last: '',
+          limit: 0,
+          query: '',
+          sort: '',
+          observer: ''
+        }
+        
+        assert_raises Hive::ArgumentError do
+          @api.list_communities(options)
+        end
+      end
+    end
+    
+    def test_list_communities
+      vcr_cassette('bridge_list_communities', record: :once) do
+        options = {
+          last: '',
+          limit: 1,
+          query: '',
+          sort: 'rank',
+          observer: 'alice'
+        }
+        
+        @api.list_communities(options) do |result|
+          assert_equal Hashie::Array, result.class
+        end
+      end
+    end
+    
+    def test_list_pop_communities
+      skip 'not implemented'
+      
+      vcr_cassette('bridge_list_pop_communities', record: :once) do
+        options = {
+          limit: 1
+        }
+        
+        assert_nil @api.list_pop_communities(options)
+      end
+    end
+    
+    def test_list_pop_communities_over_limit
+      skip 'not implemented'
+      
+      vcr_cassette('bridge_list_pop_communities_over_limit', record: :once) do
+        options = {
+          limit: 26
+        }
+        
+        assert_nil @api.list_pop_communities(options)
+      end
+    end
+  end
+  
+  def test_list_subscribers
+    vcr_cassette('bridge_list_subscribers', record: :once) do
+      options = {
+        community: 'hive-100525'
+      }
+      
+      @api.list_subscribers(options) do |result|
+        assert_equal Hashie::Array, result.class
+      end
+    end
   end
 end