mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-01-06 23:52:12 +01:00
Merge pull request #1402 from scm-manager/bugfix/rest-download
user agents are not longer set to be browsers by default
This commit is contained in:
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Internal server error for git sub modules without tree object ([#1397](https://github.com/scm-manager/scm-manager/pull/1397))
|
||||
- Do not expose subversion commit with id 0 ([#1395](https://github.com/scm-manager/scm-manager/pull/1395))
|
||||
- Disable cloning repositories via ssh for anonymous users ([#1403](https://github.com/scm-manager/scm-manager/pull/1403))
|
||||
- Support anonymous file download through rest api for non-browser clients (e.g. curl or postman) when anonymous mode is set to protocol-only ([#1402](https://github.com/scm-manager/scm-manager/pull/1402))
|
||||
- SVN diff with property changes ([#1400](https://github.com/scm-manager/scm-manager/pull/1400))
|
||||
- Branches link in repository overview ([#1404](https://github.com/scm-manager/scm-manager/pull/1404))
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.web;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
@@ -37,7 +37,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The software agent that is acting on behalf of a user. The user agent
|
||||
* The software agent that is acting on behalf of a user. The user agent
|
||||
* represents a browser or one of the repository client (svn, git or hg).
|
||||
*
|
||||
* @author Sebastian Sdorra <s.sdorra@gmail.com>
|
||||
@@ -49,17 +49,16 @@ public final class UserAgent
|
||||
/**
|
||||
* Constructs a new user agent
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* @param browser
|
||||
* @param name
|
||||
* @param basicAuthenticationCharset
|
||||
* @param browser
|
||||
*/
|
||||
private UserAgent(String name, boolean browser,
|
||||
Charset basicAuthenticationCharset)
|
||||
private UserAgent(String name, Charset basicAuthenticationCharset, boolean browser, boolean scmClient)
|
||||
{
|
||||
this.name = checkNotNull(name);
|
||||
this.browser = browser;
|
||||
this.basicAuthenticationCharset = checkNotNull(basicAuthenticationCharset);
|
||||
this.browser = browser;
|
||||
this.scmClient = scmClient;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
@@ -71,8 +70,30 @@ public final class UserAgent
|
||||
* @param name name of the UserAgent
|
||||
*
|
||||
* @return builder for UserAgent
|
||||
*
|
||||
* @deprecated Use {@link #browser(String)}, {@link #scmClient(String)} or {@link #other(String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static Builder builder(String name)
|
||||
{
|
||||
return other(name);
|
||||
}
|
||||
|
||||
public static Builder browser(String name)
|
||||
{
|
||||
final Builder builder = new Builder(name);
|
||||
builder.browser = true;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static Builder scmClient(String name)
|
||||
{
|
||||
final Builder builder = new Builder(name);
|
||||
builder.scmClient = true;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static Builder other(String name)
|
||||
{
|
||||
return new Builder(name);
|
||||
}
|
||||
@@ -127,7 +148,7 @@ public final class UserAgent
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the {@link Charset}, which is used to decode the basic
|
||||
* Returns the {@link Charset}, which is used to decode the basic
|
||||
* authentication header.
|
||||
*
|
||||
* @return {@link Charset} for basic authentication
|
||||
@@ -152,13 +173,23 @@ public final class UserAgent
|
||||
* Returns {@code true} if UserAgent is a browser.
|
||||
*
|
||||
*
|
||||
* @return {@code true} if UserAgent is a browser
|
||||
* @return {@code true} if UserAgent is a browser
|
||||
*/
|
||||
public boolean isBrowser()
|
||||
{
|
||||
return browser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if UserAgent is an scm client (e.g. git, svn or hg).
|
||||
*
|
||||
*
|
||||
* @return {@code true} if UserAgent is an scm client
|
||||
*/
|
||||
public boolean isScmClient() {
|
||||
return scmClient;
|
||||
}
|
||||
|
||||
//~--- inner classes --------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -204,7 +235,10 @@ public final class UserAgent
|
||||
* @param browser {@code true} for a browser
|
||||
*
|
||||
* @return {@code this}
|
||||
*
|
||||
* @deprecated Use {@link #browser(String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder browser(boolean browser)
|
||||
{
|
||||
this.browser = browser;
|
||||
@@ -215,12 +249,11 @@ public final class UserAgent
|
||||
/**
|
||||
* Builds the {@link UserAgent}.
|
||||
*
|
||||
*
|
||||
* @return new {@link UserAgent}
|
||||
*/
|
||||
public UserAgent build()
|
||||
{
|
||||
return new UserAgent(name, browser, basicAuthenticationCharset);
|
||||
return new UserAgent(name, basicAuthenticationCharset, browser, scmClient);
|
||||
}
|
||||
|
||||
//~--- fields -------------------------------------------------------------
|
||||
@@ -229,7 +262,10 @@ public final class UserAgent
|
||||
private final String name;
|
||||
|
||||
/** indicator for browsers */
|
||||
private boolean browser = true;
|
||||
private boolean browser = false;
|
||||
|
||||
/** indicator for browsers */
|
||||
private boolean scmClient = false;
|
||||
|
||||
/** basic authentication charset */
|
||||
private Charset basicAuthenticationCharset = Charsets.ISO_8859_1;
|
||||
@@ -244,6 +280,9 @@ public final class UserAgent
|
||||
/** indicator for browsers */
|
||||
private final boolean browser;
|
||||
|
||||
/** indicator for scm clients (e.g. git, hg, svn) */
|
||||
private final boolean scmClient;
|
||||
|
||||
/** name of UserAgent */
|
||||
private final String name;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public final class UserAgentParser
|
||||
|
||||
/** unknown UserAgent */
|
||||
@VisibleForTesting
|
||||
static final UserAgent UNKNOWN = UserAgent.builder("UNKNOWN").build();
|
||||
static final UserAgent UNKNOWN = UserAgent.other("UNKNOWN").build();
|
||||
|
||||
/** logger */
|
||||
private static final Logger logger =
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.web;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
@@ -89,7 +89,7 @@ public class UserAgentParserTest
|
||||
UserAgent ua = parser.parse(UA_1);
|
||||
|
||||
assertEquals(Charsets.ISO_8859_1, ua.getBasicAuthenticationCharset());
|
||||
assertTrue(ua.isBrowser());
|
||||
assertFalse(ua.isBrowser());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,11 +99,11 @@ public class UserAgentParserTest
|
||||
@Test
|
||||
public void testParse()
|
||||
{
|
||||
UserAgent ua = UserAgent.builder("UA1").build();
|
||||
UserAgent ua = UserAgent.other("UA1").build();
|
||||
|
||||
when(provider1.parseUserAgent(UA_1)).thenReturn(ua);
|
||||
|
||||
UserAgent ua2 = UserAgent.builder("UA2").build();
|
||||
UserAgent ua2 = UserAgent.other("UA2").build();
|
||||
|
||||
when(provider2.parseUserAgent(UA_2)).thenReturn(ua2);
|
||||
|
||||
@@ -120,7 +120,7 @@ public class UserAgentParserTest
|
||||
{
|
||||
when(request.getHeader(HttpUtil.HEADER_USERAGENT)).thenReturn(UA_2);
|
||||
|
||||
UserAgent ua = UserAgent.builder("UA2").build();
|
||||
UserAgent ua = UserAgent.other("UA2").build();
|
||||
|
||||
when(provider1.parseUserAgent(UA_2)).thenReturn(ua);
|
||||
assertEquals(ua, parser.parse(request));
|
||||
@@ -144,7 +144,7 @@ public class UserAgentParserTest
|
||||
@Test
|
||||
public void testParseWithCache()
|
||||
{
|
||||
UserAgent ua = UserAgent.builder("UA").build();
|
||||
UserAgent ua = UserAgent.other("UA").build();
|
||||
|
||||
when(cache.get(UA_1)).thenReturn(ua);
|
||||
assertEquals(ua, parser.parse(UA_1));
|
||||
|
||||
@@ -69,8 +69,8 @@ class HttpProtocolServletAuthenticationFilterBaseTest {
|
||||
@Mock
|
||||
private FilterChain filterChain;
|
||||
|
||||
private UserAgent nonBrowser = UserAgent.builder("i'm not a browser").browser(false).build();
|
||||
private UserAgent browser = UserAgent.builder("i am a browser").browser(true).build();
|
||||
private UserAgent nonBrowser = UserAgent.other("i'm not a browser").build();
|
||||
private UserAgent browser = UserAgent.browser("i am a browser").build();
|
||||
|
||||
@BeforeEach
|
||||
void setUpObjectUnderTest() {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.web;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
@@ -40,36 +40,32 @@ import sonia.scm.plugin.Extension;
|
||||
*/
|
||||
@Extension
|
||||
public class GitUserAgentProvider implements UserAgentProvider {
|
||||
|
||||
|
||||
private static final String PREFIX_JGIT = "jgit/";
|
||||
|
||||
@VisibleForTesting
|
||||
static final UserAgent JGIT = UserAgent.builder("JGit")
|
||||
.browser(false)
|
||||
static final UserAgent JGIT = UserAgent.scmClient("JGit")
|
||||
.basicAuthenticationCharset(Charsets.UTF_8)
|
||||
.build();
|
||||
|
||||
|
||||
private static final String PREFIX_REGULAR = "git/";
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
static final UserAgent GIT = UserAgent.builder("Git")
|
||||
.browser(false)
|
||||
static final UserAgent GIT = UserAgent.scmClient("Git")
|
||||
.basicAuthenticationCharset(Charsets.UTF_8)
|
||||
.build();
|
||||
|
||||
|
||||
private static final String PREFIX_LFS = "git-lfs/";
|
||||
|
||||
@VisibleForTesting
|
||||
static final UserAgent GIT_LFS = UserAgent.builder("Git Lfs")
|
||||
.browser(false)
|
||||
static final UserAgent GIT_LFS = UserAgent.scmClient("Git Lfs")
|
||||
.basicAuthenticationCharset(Charsets.UTF_8)
|
||||
.build();
|
||||
|
||||
private static final String SUFFIX_MSYSGIT = "msysgit";
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
static final UserAgent MSYSGIT = UserAgent.builder("msysGit")
|
||||
.browser(false)
|
||||
static final UserAgent MSYSGIT = UserAgent.scmClient("msysGit")
|
||||
.basicAuthenticationCharset(Charsets.UTF_8)
|
||||
.build();
|
||||
|
||||
@@ -80,7 +76,7 @@ public class GitUserAgentProvider implements UserAgentProvider {
|
||||
@Override
|
||||
public UserAgent parseUserAgent(String userAgentString) {
|
||||
String lowerUserAgent = toLower(userAgentString);
|
||||
|
||||
|
||||
if (isJGit(lowerUserAgent)) {
|
||||
return JGIT;
|
||||
} else if (isMsysGit(lowerUserAgent)) {
|
||||
@@ -93,23 +89,23 @@ public class GitUserAgentProvider implements UserAgentProvider {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String toLower(String value) {
|
||||
return Strings.nullToEmpty(value).toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
|
||||
private boolean isJGit(String userAgent) {
|
||||
return userAgent.startsWith(PREFIX_JGIT);
|
||||
}
|
||||
|
||||
|
||||
private boolean isMsysGit(String userAgent) {
|
||||
return userAgent.startsWith(PREFIX_REGULAR) && userAgent.contains(SUFFIX_MSYSGIT);
|
||||
}
|
||||
|
||||
|
||||
private boolean isGitLFS(String userAgent) {
|
||||
return userAgent.startsWith(PREFIX_LFS);
|
||||
}
|
||||
|
||||
|
||||
private boolean isGit(String userAgent) {
|
||||
return userAgent.startsWith(PREFIX_REGULAR);
|
||||
}
|
||||
|
||||
@@ -45,8 +45,7 @@ public class HgUserAgentProvider implements UserAgentProvider
|
||||
|
||||
/** mercurial seems to use system encoding */
|
||||
@VisibleForTesting
|
||||
static UserAgent HG = UserAgent.builder("Mercurial").browser(
|
||||
false).basicAuthenticationCharset(
|
||||
static UserAgent HG = UserAgent.scmClient("Mercurial").basicAuthenticationCharset(
|
||||
Charset.defaultCharset()).build();
|
||||
|
||||
/** Field description */
|
||||
|
||||
@@ -49,13 +49,13 @@ public final class SvnUserAgentProvider implements UserAgentProvider
|
||||
/** TortoiseSVN */
|
||||
@VisibleForTesting
|
||||
static final UserAgent TORTOISE_SVN =
|
||||
UserAgent.builder("TortoiseSVN").browser(false)
|
||||
UserAgent.scmClient("TortoiseSVN")
|
||||
.basicAuthenticationCharset(Charsets.UTF_8).build();
|
||||
|
||||
/** Subversion cli client */
|
||||
@VisibleForTesting
|
||||
static final UserAgent SVN =
|
||||
UserAgent.builder("Subversion").browser(false)
|
||||
UserAgent.scmClient("Subversion")
|
||||
.basicAuthenticationCharset(Charsets.UTF_8).build();
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
@@ -41,7 +41,7 @@ public class BrowserUserAgentProvider implements UserAgentProvider
|
||||
|
||||
/** Field description */
|
||||
@VisibleForTesting
|
||||
static final UserAgent CHROME = UserAgent.builder(
|
||||
static final UserAgent CHROME = UserAgent.browser(
|
||||
"Chrome").basicAuthenticationCharset(
|
||||
Charsets.UTF_8).build();
|
||||
|
||||
@@ -50,21 +50,21 @@ public class BrowserUserAgentProvider implements UserAgentProvider
|
||||
|
||||
/** Field description */
|
||||
@VisibleForTesting
|
||||
static final UserAgent FIREFOX = UserAgent.builder("Firefox").build();
|
||||
static final UserAgent FIREFOX = UserAgent.browser("Firefox").build();
|
||||
|
||||
/** Field description */
|
||||
private static final String FIREFOX_PATTERN = "firefox";
|
||||
|
||||
/** Field description */
|
||||
@VisibleForTesting
|
||||
static final UserAgent MSIE = UserAgent.builder("Internet Explorer").build();
|
||||
static final UserAgent MSIE = UserAgent.browser("Internet Explorer").build();
|
||||
|
||||
/** Field description */
|
||||
private static final String MSIE_PATTERN = "msie";
|
||||
|
||||
/** Field description */
|
||||
@VisibleForTesting // todo check charset
|
||||
static final UserAgent SAFARI = UserAgent.builder("Safari").build();
|
||||
static final UserAgent SAFARI = UserAgent.browser("Safari").build();
|
||||
|
||||
/** Field description */
|
||||
private static final String OPERA_PATTERN = "opera";
|
||||
@@ -74,7 +74,7 @@ public class BrowserUserAgentProvider implements UserAgentProvider
|
||||
|
||||
/** Field description */
|
||||
@VisibleForTesting // todo check charset
|
||||
static final UserAgent OPERA = UserAgent.builder(
|
||||
static final UserAgent OPERA = UserAgent.browser(
|
||||
"Opera").basicAuthenticationCharset(
|
||||
Charsets.UTF_8).build();
|
||||
|
||||
|
||||
@@ -74,10 +74,7 @@ public class HttpProtocolServlet extends HttpServlet {
|
||||
@Override
|
||||
protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
UserAgent userAgent = userAgentParser.parse(request);
|
||||
if (userAgent.isBrowser()) {
|
||||
log.trace("dispatch browser request for user agent {}", userAgent);
|
||||
dispatcher.dispatch(request, response, request.getRequestURI());
|
||||
} else {
|
||||
if (userAgent.isScmClient()) {
|
||||
String pathInfo = request.getPathInfo();
|
||||
Optional<NamespaceAndName> namespaceAndName = pathExtractor.fromUri(pathInfo);
|
||||
if (namespaceAndName.isPresent()) {
|
||||
@@ -86,6 +83,9 @@ public class HttpProtocolServlet extends HttpServlet {
|
||||
log.debug("namespace and name not found in request path {}", pathInfo);
|
||||
response.setStatus(HttpStatus.SC_BAD_REQUEST);
|
||||
}
|
||||
} else {
|
||||
log.trace("dispatch non-scm-client request for user agent {}", userAgent);
|
||||
dispatcher.dispatch(request, response, request.getRequestURI());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,15 +91,12 @@ class HttpProtocolServletTest {
|
||||
@BeforeEach
|
||||
void prepareMocks() {
|
||||
when(userAgentParser.parse(request)).thenReturn(userAgent);
|
||||
when(userAgent.isBrowser()).thenReturn(true);
|
||||
when(userAgent.isScmClient()).thenReturn(false);
|
||||
when(request.getRequestURI()).thenReturn("uri");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDispatchBrowserRequests() throws ServletException, IOException {
|
||||
when(userAgent.isBrowser()).thenReturn(true);
|
||||
when(request.getRequestURI()).thenReturn("uri");
|
||||
|
||||
servlet.service(request, response);
|
||||
|
||||
verify(dispatcher).dispatch(request, response, "uri");
|
||||
@@ -113,7 +110,7 @@ class HttpProtocolServletTest {
|
||||
@BeforeEach
|
||||
void prepareMocks() {
|
||||
when(userAgentParser.parse(request)).thenReturn(userAgent);
|
||||
when(userAgent.isBrowser()).thenReturn(false);
|
||||
when(userAgent.isScmClient()).thenReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user