{"action":"created","comment":{"url":"https://api.github.com/repos/cvmfs/cvmfs/pulls/comments/22533950","id":22533950,"diff_hunk":"@@ -1913,63 +1940,96 @@ bool DownloadManager::SortWrtGeoReply(\n   sanitizer::InputSanitizer strip_newline(\"09 ,\");\n   vector<string> reply_strings =\n     SplitString(strip_newline.Filter(reply_order), ',');\n-  vector<uint64_t> reply_vals;\n+  vector<uint64_t> tmp_vals;\n   for (unsigned i = 0; i < reply_strings.size(); ++i) {\n     if (reply_strings[i].empty())\n       return false;\n-    reply_vals.push_back(String2Uint64(reply_strings[i]));\n+    tmp_vals.push_back(String2Uint64(reply_strings[i]));\n   }\n-  if (reply_vals.size() != input_hosts->size())\n+  if (tmp_vals.size() != expected_size)\n     return false;\n \n-  // Check if reply_vals contains the number 1..n\n-  set<uint64_t> coverage(reply_vals.begin(), reply_vals.end());\n-  if (coverage.size() != reply_vals.size())\n+  // Check if tmp_vals contains the number 1..n\n+  set<uint64_t> coverage(tmp_vals.begin(), tmp_vals.end());\n+  if (coverage.size() != tmp_vals.size())\n     return false;\n   if ((*coverage.begin() != 1) || ((*coverage.end()-- != coverage.size())))\n     return false;\n \n-  vector<string> tmp(*input_hosts);\n-  for (unsigned i = 0; i < reply_vals.size(); ++i)\n-    (*input_hosts)[i] = tmp[reply_vals[i]-1];\n+  for (unsigned i = 0; i < expected_size; ++i) {\n+    (*reply_vals)[i] = tmp_vals[i] - 1;\n+  }\n   return true;\n }\n \n \n /**\n- * Parses a list of ';'- and '|'-separated proxy servers for the proxy groups.\n- * The empty string removes the proxy chain.\n+ * Parses a list of ';'- and '|'-separated proxy servers for the proxy groups,\n+ *   and a ';'-separated list of fallback proxies.\n+ * The empty string for both removes the proxy chain.\n  */\n-void DownloadManager::SetProxyChain(const string &proxy_list) {\n+void DownloadManager::SetProxyChain(const string &proxy_list,\n+                                    const string &fallback_proxy_list) {\n   pthread_mutex_lock(lock_options_);\n \n   opt_timestamp_backup_proxies_ = 0;\n   opt_timestamp_failover_proxies_ = 0;\n   delete opt_proxy_groups_;\n-  if (proxy_list == \"\") {\n+  if ((proxy_list == \"\") && (fallback_proxy_list == \"\")) {\n     opt_proxy_groups_ = NULL;\n     opt_proxy_groups_current_ = 0;\n     opt_proxy_groups_current_burned_ = 0;\n+    opt_proxy_groups_fallback_ = 0;\n     opt_num_proxies_ = 0;\n     pthread_mutex_unlock(lock_options_);\n     return;\n   }\n \n-  // Resolve server names in provided urls, skip DIRECT\n-  vector<string> urls;  // All encountered URLs\n-  vector<string> proxy_groups = SplitString(proxy_list, ';');\n+  // Resolve server names in provided urls\n+  vector<string> hostnames;  // All encountered hostnames\n+  vector<string> proxy_groups;\n+  if (proxy_list != \"\")\n+    proxy_groups = SplitString(proxy_list, ';');\n+  opt_proxy_groups_fallback_= proxy_groups.size();\n   for (unsigned i = 0; i < proxy_groups.size(); ++i) {\n     vector<string> this_group = SplitString(proxy_groups[i], '|');\n     for (unsigned j = 0; j < this_group.size(); ++j) {\n-      // Note: DIRECT strings will be \"extracted\" to an empty string and not\n-      // resolved.\n-      urls.push_back(dns::ExtractHost(this_group[j]));\n+      // Note: DIRECT strings will be \"extracted\" to an empty string.\n+      string hostname = dns::ExtractHost(this_group[j]);\n+      if ((hostname == \"\") && (fallback_proxy_list != \"\")) {\n+        // skip DIRECTs if there are fallback proxies\n+        opt_proxy_groups_fallback_--;","path":"cvmfs/download.cc","position":235,"original_position":228,"commit_id":"353e7ab05407559abe8569798c956ea4252d4b75","original_commit_id":"d372a29c8733d94ce0e5f16dcf54c2bf681d758e","user":{"login":"DrDaveD","id":2129743,"avatar_url":"https://avatars.githubusercontent.com/u/2129743?v=3","gravatar_id":"","url":"https://api.github.com/users/DrDaveD","html_url":"https://github.com/DrDaveD","followers_url":"https://api.github.com/users/DrDaveD/followers","following_url":"https://api.github.com/users/DrDaveD/following{/other_user}","gists_url":"https://api.github.com/users/DrDaveD/gists{/gist_id}","starred_url":"https://api.github.com/users/DrDaveD/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DrDaveD/subscriptions","organizations_url":"https://api.github.com/users/DrDaveD/orgs","repos_url":"https://api.github.com/users/DrDaveD/repos","events_url":"https://api.github.com/users/DrDaveD/events{/privacy}","received_events_url":"https://api.github.com/users/DrDaveD/received_events","type":"User","site_admin":false},"body":"I think you're right.  I hadn't considered that possibility because it's wrong to have DIRECT in a load balance group in the first place.  It doesn't make sense to randomly alternate between a proxy and DIRECT.  I think the thing to do is to remove DIRECTs from a group.  As a concession if there's only DIRECTs in a group as in your example, it could be translated it into one DIRECT.","created_at":"2015-01-06T16:51:40Z","updated_at":"2015-01-06T16:51:40Z","html_url":"https://github.com/cvmfs/cvmfs/pull/651#discussion_r22533950","pull_request_url":"https://api.github.com/repos/cvmfs/cvmfs/pulls/651","_links":{"self":{"href":"https://api.github.com/repos/cvmfs/cvmfs/pulls/comments/22533950"},"html":{"href":"https://github.com/cvmfs/cvmfs/pull/651#discussion_r22533950"},"pull_request":{"href":"https://api.github.com/repos/cvmfs/cvmfs/pulls/651"}}},"pull_request":{"url":"https://api.github.com/repos/cvmfs/cvmfs/pulls/651","id":26762530,"html_url":"https://github.com/cvmfs/cvmfs/pull/651","diff_url":"https://github.com/cvmfs/cvmfs/pull/651.diff","patch_url":"https://github.com/cvmfs/cvmfs/pull/651.patch","issue_url":"https://api.github.com/repos/cvmfs/cvmfs/issues/651","number":651,"state":"open","locked":false,"title":"Add support for fallback proxies","user":{"login":"DrDaveD","id":2129743,"avatar_url":"https://avatars.githubusercontent.com/u/2129743?v=3","gravatar_id":"","url":"https://api.github.com/users/DrDaveD","html_url":"https://github.com/DrDaveD","followers_url":"https://api.github.com/users/DrDaveD/followers","following_url":"https://api.github.com/users/DrDaveD/following{/other_user}","gists_url":"https://api.github.com/users/DrDaveD/gists{/gist_id}","starred_url":"https://api.github.com/users/DrDaveD/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DrDaveD/subscriptions","organizations_url":"https://api.github.com/users/DrDaveD/orgs","repos_url":"https://api.github.com/users/DrDaveD/repos","events_url":"https://api.github.com/users/DrDaveD/events{/privacy}","received_events_url":"https://api.github.com/users/DrDaveD/received_events","type":"User","site_admin":false},"body":"This pull request adds support for fallback proxies as called for in https://sft.its.cern.ch/jira/browse/CVM-708.  I chose the word \"fallback\" instead of \"backup\" because the backup proxy term was already used for another purpose.  There's a new config variable CVMFS_FALLBACK_PROXY to set a semicolon-separated list of fallback proxies, a new cvmfs_talk command 'proxy fallback' to set them on the command line, and a new libcvmfs option fallback_proxies to set them from the library.   Geo-api probing sorts them in addition to the server hosts.  SetProxyChain() sets both regular proxies and fallback proxies and GetProxyInfo() retrieves an additional piece of info that indicates the index into the proxies at which fallback proxies start.  This includes an update to the geoapi test function to also test setting and geo-sorting fallback proxies.","created_at":"2015-01-02T16:47:06Z","updated_at":"2015-01-06T16:51:40Z","closed_at":null,"merged_at":null,"merge_commit_sha":"0a56427de004348971c283d37c7215675c6a27b4","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/cvmfs/cvmfs/pulls/651/commits","review_comments_url":"https://api.github.com/repos/cvmfs/cvmfs/pulls/651/comments","review_comment_url":"https://api.github.com/repos/cvmfs/cvmfs/pulls/comments/{number}","comments_url":"https://api.github.com/repos/cvmfs/cvmfs/issues/651/comments","statuses_url":"https://api.github.com/repos/cvmfs/cvmfs/statuses/353e7ab05407559abe8569798c956ea4252d4b75","head":{"label":"DrDaveD:fallback-proxy","ref":"fallback-proxy","sha":"353e7ab05407559abe8569798c956ea4252d4b75","user":{"login":"DrDaveD","id":2129743,"avatar_url":"https://avatars.githubusercontent.com/u/2129743?v=3","gravatar_id":"","url":"https://api.github.com/users/DrDaveD","html_url":"https://github.com/DrDaveD","followers_url":"https://api.github.com/users/DrDaveD/followers","following_url":"https://api.github.com/users/DrDaveD/following{/other_user}","gists_url":"https://api.github.com/users/DrDaveD/gists{/gist_id}","starred_url":"https://api.github.com/users/DrDaveD/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DrDaveD/subscriptions","organizations_url":"https://api.github.com/users/DrDaveD/orgs","repos_url":"https://api.github.com/users/DrDaveD/repos","events_url":"https://api.github.com/users/DrDaveD/events{/privacy}","received_events_url":"https://api.github.com/users/DrDaveD/received_events","type":"User","site_admin":false},"repo":{"id":11373318,"name":"cvmfs","full_name":"DrDaveD/cvmfs","owner":{"login":"DrDaveD","id":2129743,"avatar_url":"https://avatars.githubusercontent.com/u/2129743?v=3","gravatar_id":"","url":"https://api.github.com/users/DrDaveD","html_url":"https://github.com/DrDaveD","followers_url":"https://api.github.com/users/DrDaveD/followers","following_url":"https://api.github.com/users/DrDaveD/following{/other_user}","gists_url":"https://api.github.com/users/DrDaveD/gists{/gist_id}","starred_url":"https://api.github.com/users/DrDaveD/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DrDaveD/subscriptions","organizations_url":"https://api.github.com/users/DrDaveD/orgs","repos_url":"https://api.github.com/users/DrDaveD/repos","events_url":"https://api.github.com/users/DrDaveD/events{/privacy}","received_events_url":"https://api.github.com/users/DrDaveD/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/DrDaveD/cvmfs","description":"The CernVM File System","fork":true,"url":"https://api.github.com/repos/DrDaveD/cvmfs","forks_url":"https://api.github.com/repos/DrDaveD/cvmfs/forks","keys_url":"https://api.github.com/repos/DrDaveD/cvmfs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/DrDaveD/cvmfs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/DrDaveD/cvmfs/teams","hooks_url":"https://api.github.com/repos/DrDaveD/cvmfs/hooks","issue_events_url":"https://api.github.com/repos/DrDaveD/cvmfs/issues/events{/number}","events_url":"https://api.github.com/repos/DrDaveD/cvmfs/events","assignees_url":"https://api.github.com/repos/DrDaveD/cvmfs/assignees{/user}","branches_url":"https://api.github.com/repos/DrDaveD/cvmfs/branches{/branch}","tags_url":"https://api.github.com/repos/DrDaveD/cvmfs/tags","blobs_url":"https://api.github.com/repos/DrDaveD/cvmfs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/DrDaveD/cvmfs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/DrDaveD/cvmfs/git/refs{/sha}","trees_url":"https://api.github.com/repos/DrDaveD/cvmfs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/DrDaveD/cvmfs/statuses/{sha}","languages_url":"https://api.github.com/repos/DrDaveD/cvmfs/languages","stargazers_url":"https://api.github.com/repos/DrDaveD/cvmfs/stargazers","contributors_url":"https://api.github.com/repos/DrDaveD/cvmfs/contributors","subscribers_url":"https://api.github.com/repos/DrDaveD/cvmfs/subscribers","subscription_url":"https://api.github.com/repos/DrDaveD/cvmfs/subscription","commits_url":"https://api.github.com/repos/DrDaveD/cvmfs/commits{/sha}","git_commits_url":"https://api.github.com/repos/DrDaveD/cvmfs/git/commits{/sha}","comments_url":"https://api.github.com/repos/DrDaveD/cvmfs/comments{/number}","issue_comment_url":"https://api.github.com/repos/DrDaveD/cvmfs/issues/comments/{number}","contents_url":"https://api.github.com/repos/DrDaveD/cvmfs/contents/{+path}","compare_url":"https://api.github.com/repos/DrDaveD/cvmfs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/DrDaveD/cvmfs/merges","archive_url":"https://api.github.com/repos/DrDaveD/cvmfs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/DrDaveD/cvmfs/downloads","issues_url":"https://api.github.com/repos/DrDaveD/cvmfs/issues{/number}","pulls_url":"https://api.github.com/repos/DrDaveD/cvmfs/pulls{/number}","milestones_url":"https://api.github.com/repos/DrDaveD/cvmfs/milestones{/number}","notifications_url":"https://api.github.com/repos/DrDaveD/cvmfs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/DrDaveD/cvmfs/labels{/name}","releases_url":"https://api.github.com/repos/DrDaveD/cvmfs/releases{/id}","created_at":"2013-07-12T16:38:35Z","updated_at":"2014-12-26T17:07:51Z","pushed_at":"2015-01-06T16:18:23Z","git_url":"git://github.com/DrDaveD/cvmfs.git","ssh_url":"git@github.com:DrDaveD/cvmfs.git","clone_url":"https://github.com/DrDaveD/cvmfs.git","svn_url":"https://github.com/DrDaveD/cvmfs","homepage":"http://cernvm.cern.ch/portal/filesystem","size":85626,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"devel"}},"base":{"label":"cvmfs:devel","ref":"devel","sha":"7bbd852ab91c9706bb7118fa969e78c97cf6514e","user":{"login":"cvmfs","id":1560859,"avatar_url":"https://avatars.githubusercontent.com/u/1560859?v=3","gravatar_id":"","url":"https://api.github.com/users/cvmfs","html_url":"https://github.com/cvmfs","followers_url":"https://api.github.com/users/cvmfs/followers","following_url":"https://api.github.com/users/cvmfs/following{/other_user}","gists_url":"https://api.github.com/users/cvmfs/gists{/gist_id}","starred_url":"https://api.github.com/users/cvmfs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cvmfs/subscriptions","organizations_url":"https://api.github.com/users/cvmfs/orgs","repos_url":"https://api.github.com/users/cvmfs/repos","events_url":"https://api.github.com/users/cvmfs/events{/privacy}","received_events_url":"https://api.github.com/users/cvmfs/received_events","type":"Organization","site_admin":false},"repo":{"id":3784908,"name":"cvmfs","full_name":"cvmfs/cvmfs","owner":{"login":"cvmfs","id":1560859,"avatar_url":"https://avatars.githubusercontent.com/u/1560859?v=3","gravatar_id":"","url":"https://api.github.com/users/cvmfs","html_url":"https://github.com/cvmfs","followers_url":"https://api.github.com/users/cvmfs/followers","following_url":"https://api.github.com/users/cvmfs/following{/other_user}","gists_url":"https://api.github.com/users/cvmfs/gists{/gist_id}","starred_url":"https://api.github.com/users/cvmfs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cvmfs/subscriptions","organizations_url":"https://api.github.com/users/cvmfs/orgs","repos_url":"https://api.github.com/users/cvmfs/repos","events_url":"https://api.github.com/users/cvmfs/events{/privacy}","received_events_url":"https://api.github.com/users/cvmfs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/cvmfs/cvmfs","description":"The CernVM File System","fork":false,"url":"https://api.github.com/repos/cvmfs/cvmfs","forks_url":"https://api.github.com/repos/cvmfs/cvmfs/forks","keys_url":"https://api.github.com/repos/cvmfs/cvmfs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cvmfs/cvmfs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cvmfs/cvmfs/teams","hooks_url":"https://api.github.com/repos/cvmfs/cvmfs/hooks","issue_events_url":"https://api.github.com/repos/cvmfs/cvmfs/issues/events{/number}","events_url":"https://api.github.com/repos/cvmfs/cvmfs/events","assignees_url":"https://api.github.com/repos/cvmfs/cvmfs/assignees{/user}","branches_url":"https://api.github.com/repos/cvmfs/cvmfs/branches{/branch}","tags_url":"https://api.github.com/repos/cvmfs/cvmfs/tags","blobs_url":"https://api.github.com/repos/cvmfs/cvmfs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cvmfs/cvmfs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cvmfs/cvmfs/git/refs{/sha}","trees_url":"https://api.github.com/repos/cvmfs/cvmfs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cvmfs/cvmfs/statuses/{sha}","languages_url":"https://api.github.com/repos/cvmfs/cvmfs/languages","stargazers_url":"https://api.github.com/repos/cvmfs/cvmfs/stargazers","contributors_url":"https://api.github.com/repos/cvmfs/cvmfs/contributors","subscribers_url":"https://api.github.com/repos/cvmfs/cvmfs/subscribers","subscription_url":"https://api.github.com/repos/cvmfs/cvmfs/subscription","commits_url":"https://api.github.com/repos/cvmfs/cvmfs/commits{/sha}","git_commits_url":"https://api.github.com/repos/cvmfs/cvmfs/git/commits{/sha}","comments_url":"https://api.github.com/repos/cvmfs/cvmfs/comments{/number}","issue_comment_url":"https://api.github.com/repos/cvmfs/cvmfs/issues/comments/{number}","contents_url":"https://api.github.com/repos/cvmfs/cvmfs/contents/{+path}","compare_url":"https://api.github.com/repos/cvmfs/cvmfs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cvmfs/cvmfs/merges","archive_url":"https://api.github.com/repos/cvmfs/cvmfs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cvmfs/cvmfs/downloads","issues_url":"https://api.github.com/repos/cvmfs/cvmfs/issues{/number}","pulls_url":"https://api.github.com/repos/cvmfs/cvmfs/pulls{/number}","milestones_url":"https://api.github.com/repos/cvmfs/cvmfs/milestones{/number}","notifications_url":"https://api.github.com/repos/cvmfs/cvmfs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cvmfs/cvmfs/labels{/name}","releases_url":"https://api.github.com/repos/cvmfs/cvmfs/releases{/id}","created_at":"2012-03-21T09:10:41Z","updated_at":"2015-01-06T16:49:51Z","pushed_at":"2015-01-06T16:49:51Z","git_url":"git://github.com/cvmfs/cvmfs.git","ssh_url":"git@github.com:cvmfs/cvmfs.git","clone_url":"https://github.com/cvmfs/cvmfs.git","svn_url":"https://github.com/cvmfs/cvmfs","homepage":"http://cernvm.cern.ch/portal/filesystem","size":92175,"stargazers_count":28,"watchers_count":28,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":24,"mirror_url":null,"open_issues_count":7,"forks":24,"open_issues":7,"watchers":28,"default_branch":"devel"}},"_links":{"self":{"href":"https://api.github.com/repos/cvmfs/cvmfs/pulls/651"},"html":{"href":"https://github.com/cvmfs/cvmfs/pull/651"},"issue":{"href":"https://api.github.com/repos/cvmfs/cvmfs/issues/651"},"comments":{"href":"https://api.github.com/repos/cvmfs/cvmfs/issues/651/comments"},"review_comments":{"href":"https://api.github.com/repos/cvmfs/cvmfs/pulls/651/comments"},"review_comment":{"href":"https://api.github.com/repos/cvmfs/cvmfs/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/cvmfs/cvmfs/pulls/651/commits"},"statuses":{"href":"https://api.github.com/repos/cvmfs/cvmfs/statuses/353e7ab05407559abe8569798c956ea4252d4b75"}}}}