diff --git a/backend/src/main/java/io/metersphere/base/domain/FucTestLog.java b/backend/src/main/java/io/metersphere/base/domain/FucTestLog.java new file mode 100644 index 0000000000000000000000000000000000000000..ca981eb1bdb5ab6341924c8f448933bd6be24b61 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/FucTestLog.java @@ -0,0 +1,23 @@ +package io.metersphere.base.domain; + +public class FucLog { + + private String seleniumLog; + private String browserDriverLog; + + public String getSeleniumLog() { + return seleniumLog; + } + + public void setSeleniumLog(String seleniumLog) { + this.seleniumLog = seleniumLog; + } + + public String getBrowserDriverLog() { + return browserDriverLog; + } + + public void setBrowserDriverLog(String browserDriverLog) { + this.browserDriverLog = browserDriverLog; + } +} diff --git a/backend/src/main/java/io/metersphere/base/domain/ZaleniumTest.java b/backend/src/main/java/io/metersphere/base/domain/ZaleniumTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0c95af241c881e5b9ece292c3024a4270bf1da88 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/ZaleniumTest.java @@ -0,0 +1,4 @@ +package io.metersphere.base.domain; + +public class ZaleniumTest { +} diff --git a/backend/src/main/java/io/metersphere/config/ProxyServletConfiguration.java b/backend/src/main/java/io/metersphere/config/ProxyServletConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..df124ad61c4685197d9235c8d8d12f8a7b133e72 --- /dev/null +++ b/backend/src/main/java/io/metersphere/config/ProxyServletConfiguration.java @@ -0,0 +1,21 @@ +package io.metersphere.config; + +import io.metersphere.proxy.ProxyServlet; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +public class SolrProxyServletConfiguration { + + @Bean + public ServletRegistrationBean servletRegistrationBean(){ + ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ProxyServlet(), "/solr/*"); +// servletRegistrationBean.addInitParameter("targetUri", "http://localhost:4444"); +// servletRegistrationBean.addInitParameter(ProxyServlet.P_LOG, "false"); + return servletRegistrationBean; + } + +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/config/RestTemplateConfig.java b/backend/src/main/java/io/metersphere/config/RestTemplateConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..143ac4c5465a3b5521d6515a6c7f234f0cdb79dc --- /dev/null +++ b/backend/src/main/java/io/metersphere/config/RestTemplateConfig.java @@ -0,0 +1,4 @@ +package io.metersphere.config; + +public class RestTemplateConfig { +} diff --git a/backend/src/main/java/io/metersphere/job/ZaleniumJob.java b/backend/src/main/java/io/metersphere/job/ZaleniumJob.java new file mode 100644 index 0000000000000000000000000000000000000000..0930b153d82efadcb28e78e62a6a776b6748e680 --- /dev/null +++ b/backend/src/main/java/io/metersphere/job/ZaleniumJob.java @@ -0,0 +1,4 @@ +package io.metersphere.job; + +public class ZaleniumJob { +} diff --git a/backend/src/main/java/io/metersphere/proxy/ProxyServlet.java b/backend/src/main/java/io/metersphere/proxy/ProxyServlet.java new file mode 100644 index 0000000000000000000000000000000000000000..bafff9bb4ca022e9f5a5b3fe5e110cb08b3fd359 --- /dev/null +++ b/backend/src/main/java/io/metersphere/proxy/ProxyServlet.java @@ -0,0 +1,680 @@ +package io.metersphere.proxy; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.CookieSpecs; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.AbortableHttpRequest; +import org.apache.http.client.utils.URIUtils; +import org.apache.http.entity.InputStreamEntity; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicHttpEntityEnclosingRequest; +import org.apache.http.message.BasicHttpRequest; +import org.apache.http.message.HeaderGroup; +import org.apache.http.util.EntityUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.Closeable; +import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpCookie; +import java.net.URI; +import java.util.BitSet; +import java.util.Enumeration; +import java.util.Formatter; +import java.util.List; + +/** + * An HTTP reverse proxy/gateway servlet. It is designed to be extended for customization + * if desired. Most of the work is handled by + * Apache HttpClient. + *
+ * There are alternatives to a servlet based proxy such as Apache mod_proxy if that is available to you. However + * this servlet is easily customizable by Java, secure-able by your web application's security (e.g. spring-security), + * portable across servlet engines, and is embeddable into another web application. + *
+ *+ * Inspiration: http://httpd.apache.org/docs/2.0/mod/mod_proxy.html + *
+ * + * @author David Smiley dsmiley@apache.org + */ +@SuppressWarnings({ "deprecation", "serial" }) +public class ProxyServlet extends HttpServlet { + + /* INIT PARAMETER NAME CONSTANTS */ + + /** A boolean parameter name to enable logging of input and target URLs to the servlet log. */ + public static final String P_LOG = "log"; + + /** A boolean parameter name to enable forwarding of the client IP */ + public static final String P_FORWARDEDFOR = "forwardip"; + + /** A boolean parameter name to keep HOST parameter as-is */ + public static final String P_PRESERVEHOST = "preserveHost"; + + /** A boolean parameter name to keep COOKIES as-is */ + public static final String P_PRESERVECOOKIES = "preserveCookies"; + + /** A boolean parameter name to have auto-handle redirects */ + public static final String P_HANDLEREDIRECTS = "http.protocol.handle-redirects"; // ClientPNames.HANDLE_REDIRECTS + + /** A integer parameter name to set the socket connection timeout (millis) */ + public static final String P_CONNECTTIMEOUT = "http.socket.timeout"; // CoreConnectionPNames.SO_TIMEOUT + + /** A integer parameter name to set the socket read timeout (millis) */ + public static final String P_READTIMEOUT = "http.read.timeout"; + + /** A boolean parameter whether to use JVM-defined system properties to configure various networking aspects. */ + public static final String P_USESYSTEMPROPERTIES = "useSystemProperties"; + + /** The parameter name for the target (destination) URI to proxy to. */ + protected static final String P_TARGET_URI = "targetUri"; + protected static final String ATTR_TARGET_URI = + ProxyServlet.class.getSimpleName() + ".targetUri"; + protected static final String ATTR_TARGET_HOST = + ProxyServlet.class.getSimpleName() + ".targetHost"; + + /* MISC */ + + protected boolean doLog = false; + protected boolean doForwardIP = true; + /** User agents shouldn't send the url fragment but what if it does? */ + protected boolean doSendUrlFragment = true; + protected boolean doPreserveHost = false; + protected boolean doPreserveCookies = false; + protected boolean doHandleRedirects = false; + protected boolean useSystemProperties = false; + protected int connectTimeout = -1; + protected int readTimeout = -1; + + //These next 3 are cached here, and should only be referred to in initialization logic. See the + // ATTR_* parameters. + /** From the configured parameter "targetUri". */ + protected String targetUri; + protected URI targetUriObj;//new URI(targetUri) + protected HttpHost targetHost;//URIUtils.extractHost(targetUriObj); + + private HttpClient proxyClient; + + @Override + public String getServletInfo() { + return "A proxy servlet by David Smiley, dsmiley@apache.org"; + } + + + protected String getTargetUri(HttpServletRequest servletRequest) { + return (String) servletRequest.getAttribute(ATTR_TARGET_URI); + } + + protected HttpHost getTargetHost(HttpServletRequest servletRequest) { + return (HttpHost) servletRequest.getAttribute(ATTR_TARGET_HOST); + } + + /** + * Reads a configuration parameter. By default it reads servlet init parameters but + * it can be overridden. + */ + protected String getConfigParam(String key) { + return getServletConfig().getInitParameter(key); + } + + @Override + public void init() throws ServletException { + String doLogStr = getConfigParam(P_LOG); + if (doLogStr != null) { + this.doLog = Boolean.parseBoolean(doLogStr); + } + + String doForwardIPString = getConfigParam(P_FORWARDEDFOR); + if (doForwardIPString != null) { + this.doForwardIP = Boolean.parseBoolean(doForwardIPString); + } + + String preserveHostString = getConfigParam(P_PRESERVEHOST); + if (preserveHostString != null) { + this.doPreserveHost = Boolean.parseBoolean(preserveHostString); + } + + String preserveCookiesString = getConfigParam(P_PRESERVECOOKIES); + if (preserveCookiesString != null) { + this.doPreserveCookies = Boolean.parseBoolean(preserveCookiesString); + } + + String handleRedirectsString = getConfigParam(P_HANDLEREDIRECTS); + if (handleRedirectsString != null) { + this.doHandleRedirects = Boolean.parseBoolean(handleRedirectsString); + } + + String connectTimeoutString = getConfigParam(P_CONNECTTIMEOUT); + if (connectTimeoutString != null) { + this.connectTimeout = Integer.parseInt(connectTimeoutString); + } + + String readTimeoutString = getConfigParam(P_READTIMEOUT); + if (readTimeoutString != null) { + this.readTimeout = Integer.parseInt(readTimeoutString); + } + + String useSystemPropertiesString = getConfigParam(P_USESYSTEMPROPERTIES); + if (useSystemPropertiesString != null) { + this.useSystemProperties = Boolean.parseBoolean(useSystemPropertiesString); + } + + initTarget();//sets target* + + proxyClient = createHttpClient(buildRequestConfig()); + } + + /** + * Sub-classes can override specific behaviour of {@link org.apache.http.client.config.RequestConfig}. + */ + protected RequestConfig buildRequestConfig() { + return RequestConfig.custom() + .setRedirectsEnabled(doHandleRedirects) + .setCookieSpec(CookieSpecs.IGNORE_COOKIES) // we handle them in the servlet instead + .setConnectTimeout(connectTimeout) + .setSocketTimeout(readTimeout) + .build(); + } + + protected void initTarget() throws ServletException { + targetUri = getConfigParam(P_TARGET_URI); + if (targetUri == null) + throw new ServletException(P_TARGET_URI+" is required."); + //test it's valid + try { + targetUriObj = new URI(targetUri); + } catch (Exception e) { + throw new ServletException("Trying to process targetUri init parameter: "+e,e); + } + targetHost = URIUtils.extractHost(targetUriObj); + } + + /** + * Called from {@link #init(javax.servlet.ServletConfig)}. + * HttpClient offers many opportunities for customization. + * In any case, it should be thread-safe. + */ + protected HttpClient createHttpClient(final RequestConfig requestConfig) { + HttpClientBuilder clientBuilder = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig); + if (useSystemProperties) + clientBuilder = clientBuilder.useSystemProperties(); + return clientBuilder.build(); + } + + /** + * The http client used. + * @see #createHttpClient(RequestConfig) + */ + protected HttpClient getProxyClient() { + return proxyClient; + } + + @Override + public void destroy() { + //Usually, clients implement Closeable: + if (proxyClient instanceof Closeable) { + try { + ((Closeable) proxyClient).close(); + } catch (IOException e) { + log("While destroying servlet, shutting down HttpClient: "+e, e); + } + } else { + //Older releases require we do this: + if (proxyClient != null) + proxyClient.getConnectionManager().shutdown(); + } + super.destroy(); + } + + @Override + protected void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse) + throws ServletException, IOException { + //initialize request attributes from caches if unset by a subclass by this point + if (servletRequest.getAttribute(ATTR_TARGET_URI) == null) { + servletRequest.setAttribute(ATTR_TARGET_URI, targetUri); + } + if (servletRequest.getAttribute(ATTR_TARGET_HOST) == null) { + servletRequest.setAttribute(ATTR_TARGET_HOST, targetHost); + } + + // Make the Request + //note: we won't transfer the protocol version because I'm not sure it would truly be compatible + String method = servletRequest.getMethod(); + String proxyRequestUri = rewriteUrlFromRequest(servletRequest); + HttpRequest proxyRequest; + //spec: RFC 2616, sec 4.3: either of these two headers signal that there is a message body. + if (servletRequest.getHeader(HttpHeaders.CONTENT_LENGTH) != null || + servletRequest.getHeader(HttpHeaders.TRANSFER_ENCODING) != null) { + proxyRequest = newProxyRequestWithEntity(method, proxyRequestUri, servletRequest); + } else { + proxyRequest = new BasicHttpRequest(method, proxyRequestUri); + } + + copyRequestHeaders(servletRequest, proxyRequest); + + setXForwardedForHeader(servletRequest, proxyRequest); + + HttpResponse proxyResponse = null; + try { + // Execute the request + proxyResponse = doExecute(servletRequest, servletResponse, proxyRequest); + + // Process the response: + + // Pass the response code. This method with the "reason phrase" is deprecated but it's the + // only way to pass the reason along too. + int statusCode = proxyResponse.getStatusLine().getStatusCode(); + //noinspection deprecation + servletResponse.setStatus(statusCode, proxyResponse.getStatusLine().getReasonPhrase()); + + // Copying response headers to make sure SESSIONID or other Cookie which comes from the remote + // server will be saved in client when the proxied url was redirected to another one. + // See issue [#51](https://github.com/mitre/HTTP-Proxy-Servlet/issues/51) + copyResponseHeaders(proxyResponse, servletRequest, servletResponse); + + if (statusCode == HttpServletResponse.SC_NOT_MODIFIED) { + // 304 needs special handling. See: + // http://www.ics.uci.edu/pub/ietf/http/rfc1945.html#Code304 + // Don't send body entity/content! + servletResponse.setIntHeader(HttpHeaders.CONTENT_LENGTH, 0); + } else { + // Send the content to the client + copyResponseEntity(proxyResponse, servletResponse, proxyRequest, servletRequest); + } + + } catch (Exception e) { + handleRequestException(proxyRequest, e); + } finally { + // make sure the entire entity was consumed, so the connection is released + if (proxyResponse != null) + EntityUtils.consumeQuietly(proxyResponse.getEntity()); + //Note: Don't need to close servlet outputStream: + // http://stackoverflow.com/questions/1159168/should-one-call-close-on-httpservletresponse-getoutputstream-getwriter + } + } + + protected void handleRequestException(HttpRequest proxyRequest, Exception e) throws ServletException, IOException { + //abort request, according to best practice with HttpClient + if (proxyRequest instanceof AbortableHttpRequest) { + AbortableHttpRequest abortableHttpRequest = (AbortableHttpRequest) proxyRequest; + abortableHttpRequest.abort(); + } + if (e instanceof RuntimeException) + throw (RuntimeException)e; + if (e instanceof ServletException) + throw (ServletException)e; + //noinspection ConstantConditions + if (e instanceof IOException) + throw (IOException) e; + throw new RuntimeException(e); + } + + protected HttpResponse doExecute(HttpServletRequest servletRequest, HttpServletResponse servletResponse, + HttpRequest proxyRequest) throws IOException { + if (doLog) { + log("proxy " + servletRequest.getMethod() + " uri: " + servletRequest.getRequestURI() + " -- " + + proxyRequest.getRequestLine().getUri()); + } + return proxyClient.execute(getTargetHost(servletRequest), proxyRequest); + } + + protected HttpRequest newProxyRequestWithEntity(String method, String proxyRequestUri, + HttpServletRequest servletRequest) + throws IOException { + HttpEntityEnclosingRequest eProxyRequest = + new BasicHttpEntityEnclosingRequest(method, proxyRequestUri); + // Add the input entity (streamed) + // note: we don't bother ensuring we close the servletInputStream since the container handles it + eProxyRequest.setEntity( + new InputStreamEntity(servletRequest.getInputStream(), getContentLength(servletRequest))); + return eProxyRequest; + } + + // Get the header value as a long in order to more correctly proxy very large requests + private long getContentLength(HttpServletRequest request) { + String contentLengthHeader = request.getHeader("Content-Length"); + if (contentLengthHeader != null) { + return Long.parseLong(contentLengthHeader); + } + return -1L; + } + + protected void closeQuietly(Closeable closeable) { + try { + closeable.close(); + } catch (IOException e) { + log(e.getMessage(), e); + } + } + + /** These are the "hop-by-hop" headers that should not be copied. + * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html + * I use an HttpClient HeaderGroup class instead of Set<String> because this + * approach does case insensitive lookup faster. + */ + protected static final HeaderGroup hopByHopHeaders; + static { + hopByHopHeaders = new HeaderGroup(); + String[] headers = new String[] { + "Connection", "Keep-Alive", "Proxy-Authenticate", "Proxy-Authorization", + "TE", "Trailers", "Transfer-Encoding", "Upgrade" }; + for (String header : headers) { + hopByHopHeaders.addHeader(new BasicHeader(header, null)); + } + } + + /** + * Copy request headers from the servlet client to the proxy request. + * This is easily overridden to add your own. + */ + protected void copyRequestHeaders(HttpServletRequest servletRequest, HttpRequest proxyRequest) { + // Get an Enumeration of all of the header names sent by the client + @SuppressWarnings("unchecked") + EnumerationUnfortunately, an incoming URI sometimes has characters disallowed by the spec. HttpClient
+ * insists that the outgoing proxied request has a valid URI because it uses Java's {@link URI}.
+ * To be more forgiving, we must escape the problematic characters. See the URI class for the
+ * spec.
+ *
+ * @param in example: name=value&foo=bar#fragment
+ * @param encodePercent determine whether percent characters need to be encoded
+ */
+ protected static CharSequence encodeUriQuery(CharSequence in, boolean encodePercent) {
+ //Note that I can't simply use URI.java to encode because it will escape pre-existing escaped things.
+ StringBuilder outBuf = null;
+ Formatter formatter = null;
+ for(int i = 0; i < in.length(); i++) {
+ char c = in.charAt(i);
+ boolean escape = true;
+ if (c < 128) {
+ if (asciiQueryChars.get((int)c) && !(encodePercent && c == '%')) {
+ escape = false;
+ }
+ } else if (!Character.isISOControl(c) && !Character.isSpaceChar(c)) {//not-ascii
+ escape = false;
+ }
+ if (!escape) {
+ if (outBuf != null)
+ outBuf.append(c);
+ } else {
+ //escape
+ if (outBuf == null) {
+ outBuf = new StringBuilder(in.length() + 5*3);
+ outBuf.append(in,0,i);
+ formatter = new Formatter(outBuf);
+ }
+ //leading %, 0 padded, width 2, capital hex
+ formatter.format("%%%02X",(int)c);//TODO
+ }
+ }
+ return outBuf != null ? outBuf : in;
+ }
+
+ protected static final BitSet asciiQueryChars;
+ static {
+ char[] c_unreserved = "_-!.~'()*".toCharArray();//plus alphanum
+ char[] c_punct = ",;:$&+=".toCharArray();
+ char[] c_reserved = "?/[]@".toCharArray();//plus punct
+
+ asciiQueryChars = new BitSet(128);
+ for(char c = 'a'; c <= 'z'; c++) asciiQueryChars.set((int)c);
+ for(char c = 'A'; c <= 'Z'; c++) asciiQueryChars.set((int)c);
+ for(char c = '0'; c <= '9'; c++) asciiQueryChars.set((int)c);
+ for(char c : c_unreserved) asciiQueryChars.set((int)c);
+ for(char c : c_punct) asciiQueryChars.set((int)c);
+ for(char c : c_reserved) asciiQueryChars.set((int)c);
+
+ asciiQueryChars.set((int)'%');//leave existing percent escapes in place
+ }
+
+}
\ No newline at end of file
diff --git a/backend/src/main/java/io/metersphere/service/ZaleniumService.java b/backend/src/main/java/io/metersphere/service/ZaleniumService.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e5b937bfee7b56d4fdd72133ad659ba716c1a27
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/service/ZaleniumService.java
@@ -0,0 +1,4 @@
+package io.metersphere.service;
+
+public class ZaleniumService {
+}
diff --git a/backend/src/test/java/io/metersphere/ZaleniumTest.java b/backend/src/test/java/io/metersphere/ZaleniumTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5751d8a9edb48b84502fc040f1243e3e17e176fe
--- /dev/null
+++ b/backend/src/test/java/io/metersphere/ZaleniumTest.java
@@ -0,0 +1,4 @@
+package io.metersphere;
+
+public class ZaleniumTest {
+}
diff --git a/frontend/package.json b/frontend/package.json
index 8f5054cf9d17f551ebc14dbc85afb6c60301d607..39390157657cadea9a81c5799cb8dd1c01bb2ce0 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -41,7 +41,8 @@
"eslint:recommended"
],
"rules": {
- "vue/no-unused-components": "off"
+ "vue/no-unused-components": "off",
+ "no-console":"off"
},
"parserOptions": {
"parser": "babel-eslint"
diff --git a/frontend/src/business/components/functional/report/FunctionalReportView.vue b/frontend/src/business/components/functional/report/FunctionalReportView.vue
index ae562357ca749c2eb165a4c7ae0c962b997b72f7..ce2fc51e3d06dfff1655b24a57a7a8e43ae97a5b 100644
--- a/frontend/src/business/components/functional/report/FunctionalReportView.vue
+++ b/frontend/src/business/components/functional/report/FunctionalReportView.vue
@@ -6,9 +6,9 @@