diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index b85417c23fba2d2d1ac93c867688ff84acb30a9a..78c7462286d64dc3c77c12b2965f24221822b632 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -544,12 +544,48 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
                                       << "." << LLAssetType::lookup(type) << LL_ENDL;
         }
         
-        // This can be overridden by subclasses
         _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority);     
     }
 
 }
 
+// static
+void LLAssetStorage::removeAndCallbackPendingDownloads(S32 result, const LLUUID& file_id, LLAssetType::EType file_type,
+                                                       const LLUUID& callback_id, LLAssetType::EType callback_type,
+                                                       LLExtStat ext_status)
+{
+    // find and callback ALL pending requests for this UUID
+    // SJB: We process the callbacks in reverse order, I do not know if this is important,
+    //      but I didn't want to mess with it.
+    request_list_t requests;
+    for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin();
+         iter != gAssetStorage->mPendingDownloads.end();  )
+    {
+        request_list_t::iterator curiter = iter++;
+        LLAssetRequest* tmp = *curiter;
+        if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type))
+        {
+            requests.push_front(tmp);
+            iter = gAssetStorage->mPendingDownloads.erase(curiter);
+        }
+    }
+    for (request_list_t::iterator iter = requests.begin();
+         iter != requests.end();  )
+    {
+        request_list_t::iterator curiter = iter++;
+        LLAssetRequest* tmp = *curiter;
+        if (tmp->mDownCallback)
+        {
+            if (result != LL_ERR_NOERR)
+            {
+                add(sFailedDownloadCount, 1);
+            }
+            tmp->mDownCallback(gAssetStorage->mVFS, callback_id, callback_type, tmp->mUserData, result, ext_status);
+        }
+        delete tmp;
+    }
+}
+
 void LLAssetStorage::downloadCompleteCallback(
     S32 result,
     const LLUUID& file_id,
@@ -608,36 +644,7 @@ void LLAssetStorage::downloadCompleteCallback(
         }
     }
 
-    // find and callback ALL pending requests for this UUID
-    // SJB: We process the callbacks in reverse order, I do not know if this is important,
-    //      but I didn't want to mess with it.
-    request_list_t requests;
-    for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin();
-         iter != gAssetStorage->mPendingDownloads.end();  )
-    {
-        request_list_t::iterator curiter = iter++;
-        LLAssetRequest* tmp = *curiter;
-        if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type))
-        {
-            requests.push_front(tmp);
-            iter = gAssetStorage->mPendingDownloads.erase(curiter);
-        }
-    }
-    for (request_list_t::iterator iter = requests.begin();
-         iter != requests.end();  )
-    {
-        request_list_t::iterator curiter = iter++;
-        LLAssetRequest* tmp = *curiter;
-        if (tmp->mDownCallback)
-        {
-            if (result != LL_ERR_NOERR)
-            {
-                add(sFailedDownloadCount, 1);
-            }
-            tmp->mDownCallback(gAssetStorage->mVFS, callback_id, callback_type, tmp->mUserData, result, ext_status);
-        }
-        delete tmp;
-    }
+    removeAndCallbackPendingDownloads(result, file_id, file_type, callback_id, callback_type, ext_status);
 }
 
 void LLAssetStorage::getEstateAsset(
diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h
index 853387a5955f9e9794bd5ba1074a023ef6fe13ef..e1c6028fa01610d9322023de958812ef0b63a48b 100644
--- a/indra/llmessage/llassetstorage.h
+++ b/indra/llmessage/llassetstorage.h
@@ -319,6 +319,10 @@ class LLAssetStorage
                               const LLUUID& asset_id);
 
 
+    static void removeAndCallbackPendingDownloads(S32 result, const LLUUID& file_id, LLAssetType::EType file_type,
+                                                  const LLUUID& callback_id, LLAssetType::EType callback_type,
+                                                  LLExtStat ext_status);
+    
 	// download process callbacks
 	static void downloadCompleteCallback(
 		S32 result,
diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp
index b5e68c0617dbd282553c8915384bfe31a9001a27..628eb9ec898282b26c5572216c3648d34e82215b 100644
--- a/indra/newview/llviewerassetstorage.cpp
+++ b/indra/newview/llviewerassetstorage.cpp
@@ -33,12 +33,16 @@
 #include "message.h"
 
 #include "llagent.h"
+#include "llviewerregion.h"
 
 // FIXME asset-http: We are the only customer for gTransferManager - the
 // whole class can be yanked once everything is http-ified.
 #include "lltransfersourceasset.h"
 #include "lltransfertargetvfile.h"
 #include "llviewerassetstats.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llsdutil.h"
 
 ///----------------------------------------------------------------------------
 /// LLViewerAssetRequest
@@ -344,6 +348,26 @@ void LLViewerAssetStorage::_queueDataRequest(
     BOOL duplicate,
     BOOL is_priority)
 {
+    if (LLAssetType::lookupFetchWithVACap(atype))
+    {
+        queueRequestHttp(uuid, atype, callback, user_data, duplicate, is_priority);
+    }
+    else
+    {
+        queueRequestUDP(uuid, atype, callback, user_data, duplicate, is_priority);
+    }
+}
+
+void LLViewerAssetStorage::queueRequestUDP(
+    const LLUUID& uuid,
+    LLAssetType::EType atype,
+    LLGetAssetCallback callback,
+    void *user_data,
+    BOOL duplicate,
+    BOOL is_priority)
+{
+    LL_DEBUGS("ViewerAsset") << "Request asset via UDP " << uuid << " type " << LLAssetType::lookup(atype) << LL_ENDL;
+
     if (mUpstreamHost.isOk())
     {
         // stash the callback info so we can find it after we get the response message
@@ -390,3 +414,97 @@ void LLViewerAssetStorage::_queueDataRequest(
     }
 }
 
+void LLViewerAssetStorage::queueRequestHttp(
+    const LLUUID& uuid,
+    LLAssetType::EType atype,
+    LLGetAssetCallback callback,
+    void *user_data,
+    BOOL duplicate,
+    BOOL is_priority)
+{
+    LL_DEBUGS("ViewerAsset") << "Request asset via HTTP " << uuid << " type " << LLAssetType::lookup(atype) << LL_ENDL;
+    std::string cap_url = gAgent.getRegion()->getCapability("ViewerAsset");
+    if (cap_url.empty())
+    {
+        LL_WARNS() << "No ViewerAsset cap found, fetch fails" << LL_ENDL;
+        // TODO: handle waiting for caps? Other failure mechanism?
+        return;
+    }
+    else
+    {
+        LL_DEBUGS("ViewerAsset") << "Will fetch via ViewerAsset cap " << cap_url << LL_ENDL;
+
+        LLViewerAssetRequest *req = new LLViewerAssetRequest(uuid, atype);
+        req->mDownCallback = callback;
+        req->mUserData = user_data;
+        req->mIsPriority = is_priority;
+        if (!duplicate)
+        {
+            // Only collect metrics for non-duplicate requests.  Others 
+            // are piggy-backing and will artificially lower averages.
+            req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+        }
+        mPendingDownloads.push_back(req);
+
+        // TODO AssetStatsFF stuff from UDP too?
+        
+        // This is the same as the current UDP logic - don't re-request a duplicate.
+        if (!duplicate)
+        {
+            LLCoros::instance().launch("LLViewerAssetStorage::assetRequestCoro",
+                                       boost::bind(&LLViewerAssetStorage::assetRequestCoro, this, uuid, atype, callback, user_data, duplicate, is_priority));
+        }
+    }
+}
+
+void LLViewerAssetStorage::assetRequestCoro(
+    const LLUUID& uuid,
+    LLAssetType::EType atype,
+    LLGetAssetCallback callback,
+    void *user_data,
+    BOOL duplicate,
+    BOOL is_priority)
+{
+    std::string url = getAssetURL(uuid,atype);
+    LL_DEBUGS("ViewerAsset") << "request url: " << url << LL_ENDL;
+    
+    // TODO: what about duplicates?
+    
+    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("assetRequestCoro", httpPolicy));
+    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+    LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+
+    LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts);
+
+    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+    if (!status)
+    {
+        // TODO: handle failures
+        LL_DEBUGS("ViewerAsset") << "request failed, status " << status.toTerseString() << ", now what?" << LL_ENDL;
+    }
+    else
+    {
+        LL_DEBUGS("ViewerAsset") << "request succeeded" << LL_ENDL;
+
+        LL_DEBUGS("ViewerAsset") << "result: " << ll_pretty_print_sd(httpResults) << LL_ENDL;
+
+        // TODO: Use asset data to create the asset
+
+        // Clean up pending downloads and trigger callbacks
+        // TODO: what are result_code and ext_status?
+        S32 result_code = LL_ERR_NOERR;
+        LLExtStat ext_status = LL_EXSTAT_NONE;
+        removeAndCallbackPendingDownloads(result_code, uuid, atype, uuid, atype, ext_status);
+    }
+}
+
+std::string LLViewerAssetStorage::getAssetURL(const LLUUID& uuid, LLAssetType::EType atype)
+{
+    std::string cap_url = gAgent.getRegion()->getCapability("ViewerAsset");
+    std::string type_name = LLAssetType::lookup(atype);
+    std::string url = cap_url + "/?" + type_name + "_id=" + uuid.asString();
+    return url;
+}
diff --git a/indra/newview/llviewerassetstorage.h b/indra/newview/llviewerassetstorage.h
index 4643fccbc1ab12424ed700c55a347e40bd8c906c..474330c7c9196a30b2ea13afec9705298afc5410 100644
--- a/indra/newview/llviewerassetstorage.h
+++ b/indra/newview/llviewerassetstorage.h
@@ -28,7 +28,6 @@
 #define LLVIEWERASSETSTORAGE_H
 
 #include "llassetstorage.h"
-//#include "curl/curl.h"
 
 class LLVFile;
 
@@ -64,8 +63,6 @@ class LLViewerAssetStorage : public LLAssetStorage
 		F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT);
 
 protected:
-	using LLAssetStorage::_queueDataRequest;
-
 	// virtual
 	void _queueDataRequest(const LLUUID& uuid,
 						   LLAssetType::EType type,
@@ -73,6 +70,30 @@ class LLViewerAssetStorage : public LLAssetStorage
 						   void *user_data,
 						   BOOL duplicate,
 						   BOOL is_priority);
+
+    void queueRequestUDP(const LLUUID& uuid,
+                         LLAssetType::EType type,
+                         void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
+                         void *user_data,
+                         BOOL duplicate,
+                         BOOL is_priority);
+
+    void queueRequestHttp(const LLUUID& uuid,
+                          LLAssetType::EType type,
+                          void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
+                          void *user_data,
+                          BOOL duplicate,
+                          BOOL is_priority);
+
+    void assetRequestCoro(const LLUUID& uuid,
+                          LLAssetType::EType type,
+                          void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
+                          void *user_data,
+                          BOOL duplicate,
+                          BOOL is_priority);
+
+    std::string getAssetURL(const LLUUID& uuid, LLAssetType::EType atype);
+
 };
 
 #endif
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 899ab3a3717efe7984672cdb251f9a46fc256e06..0188208cfdae8856e7c9f02eb111809458e0a837 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -2895,6 +2895,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("UpdateScriptAgent");
 	capabilityNames.append("UpdateScriptTask");
 	capabilityNames.append("UploadBakedTexture");
+	capabilityNames.append("ViewerAsset"); 
 	capabilityNames.append("ViewerMetrics");
 	capabilityNames.append("ViewerStartAuction");
 	capabilityNames.append("ViewerStats");