This is an automated email from the ASF dual-hosted git repository.

dockerzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/inlong.git


The following commit(s) were added to refs/heads/master by this push:
     new 2da89aa15 [INLONG-8068][Manager] Support repeatable read for http 
request (#8075)
2da89aa15 is described below

commit 2da89aa157dae5b59417587f04c73fda394e4dd2
Author: vernedeng <[email protected]>
AuthorDate: Thu May 25 16:18:02 2023 +0800

    [INLONG-8068][Manager] Support repeatable read for http request (#8075)
    
    Co-authored-by: vernedeng <[email protected]>
---
 .../inlong/manager/web/auth/InlongShiroImpl.java   |   4 +
 .../manager/web/auth/web/AuthenticationFilter.java |   1 -
 .../web/filter/HttpServletRequestFilter.java       |  54 ++++++++
 .../inlong/manager/web/utils/HttpContextUtils.java | 111 ++++++++++++++++
 .../manager/web/utils/InlongRequestWrapper.java    | 144 +++++++++++++++++++++
 .../web/filter/HttpServletRequestFilterTest.java   |  77 +++++++++++
 6 files changed, 390 insertions(+), 1 deletion(-)

diff --git 
a/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/auth/InlongShiroImpl.java
 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/auth/InlongShiroImpl.java
index 5954a367b..178323cc8 100644
--- 
a/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/auth/InlongShiroImpl.java
+++ 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/auth/InlongShiroImpl.java
@@ -94,9 +94,13 @@ public class InlongShiroImpl implements InlongShiro {
         shiroFilterFactoryBean.setSecurityManager(securityManager);
         // anon: can be accessed by anyone, authc: only authentication is 
successful can be accessed
         Map<String, Filter> filters = new LinkedHashMap<>();
+
+        // request filter
         filters.put(FILTER_NAME_WEB, new AuthenticationFilter());
+
         shiroFilterFactoryBean.setFilters(filters);
         Map<String, String> pathDefinitions = new LinkedHashMap<>();
+
         // login, register request
         pathDefinitions.put("/api/anno/**/*", "anon");
 
diff --git 
a/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/auth/web/AuthenticationFilter.java
 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/auth/web/AuthenticationFilter.java
index d40acb7c1..60f11b772 100644
--- 
a/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/auth/web/AuthenticationFilter.java
+++ 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/auth/web/AuthenticationFilter.java
@@ -59,7 +59,6 @@ public class AuthenticationFilter implements Filter {
     public void doFilter(ServletRequest servletRequest, ServletResponse 
servletResponse, FilterChain filterChain)
             throws IOException, ServletException {
         HttpServletRequest httpServletRequest = (HttpServletRequest) 
servletRequest;
-
         Subject subject = SecurityUtils.getSubject();
         if (subject.isAuthenticated()) {
             UserInfo loginUserInfo = (UserInfo) subject.getPrincipal();
diff --git 
a/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/filter/HttpServletRequestFilter.java
 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/filter/HttpServletRequestFilter.java
new file mode 100644
index 000000000..387095324
--- /dev/null
+++ 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/filter/HttpServletRequestFilter.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.web.filter;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.inlong.manager.web.utils.InlongRequestWrapper;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * HttpServletRequestFilter
+ * Make All
+ */
+@Slf4j
+@Component
+@WebFilter
+@Order(0)
+public class HttpServletRequestFilter implements Filter {
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse 
servletResponse, FilterChain filterChain)
+            throws IOException, ServletException {
+        if (servletRequest instanceof HttpServletRequest) {
+            ServletRequest requestWrapper = new 
InlongRequestWrapper((HttpServletRequest) servletRequest);
+            filterChain.doFilter(requestWrapper, servletResponse);
+        } else {
+            filterChain.doFilter(servletRequest, servletResponse);
+        }
+    }
+}
diff --git 
a/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/utils/HttpContextUtils.java
 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/utils/HttpContextUtils.java
new file mode 100644
index 000000000..b82ab07d0
--- /dev/null
+++ 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/utils/HttpContextUtils.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.web.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * HttpContextUtils
+ */
+@Slf4j
+public class HttpContextUtils {
+
+    /**
+     * Get request params
+     * @param request
+     * @return
+     */
+    public static Map<String, String> getParameterMapAll(HttpServletRequest 
request) {
+        Enumeration<String> parameters = request.getParameterNames();
+
+        Map<String, String> params = new HashMap<>();
+        while (parameters.hasMoreElements()) {
+            String parameter = parameters.nextElement();
+            String value = request.getParameter(parameter);
+            params.put(parameter, value);
+        }
+        return params;
+    }
+
+    public static Map<String, String[]> getParameterMap(HttpServletRequest 
request) {
+        Map<String, String[]> paramMap = new HashMap<>();
+        String queryString = request.getQueryString();
+        if (StringUtils.isNotBlank(queryString)) {
+            String[] params = queryString.split("&");
+            for (int i = 0; i < params.length; i++) {
+                int splitIndex = params[i].indexOf("=");
+                if (splitIndex == -1) {
+                    continue;
+                }
+                String key = params[i].substring(0, splitIndex);
+                if (!paramMap.containsKey(key)) {
+                    if (splitIndex < params[i].length()) {
+                        String value = params[i].substring(splitIndex + 1);
+                        paramMap.put(key, new String[]{value});
+                    }
+                }
+            }
+        }
+        return paramMap;
+    }
+
+    public static Map<String, String> getHeaderMapAll(HttpServletRequest 
request) {
+        Enumeration<String> headerNames = request.getHeaderNames();
+        Map<String, String> headers = new HashMap<>();
+        while (headerNames.hasMoreElements()) {
+            String parameter = headerNames.nextElement();
+            String value = request.getHeader(parameter);
+            headers.put(parameter, value);
+        }
+        return headers;
+    }
+
+    /**
+     * Get request body
+     * @param request
+     * @return
+     */
+    public static String getBodyString(ServletRequest request) {
+        StringBuilder sb = new StringBuilder();
+        try (InputStream inputStream = request.getInputStream()) {
+            try (BufferedReader reader =
+                    new BufferedReader(new InputStreamReader(inputStream, 
StandardCharsets.UTF_8))) {
+                String line = "";
+                while ((line = reader.readLine()) != null) {
+                    sb.append(line);
+                }
+            }
+        } catch (IOException e) {
+            log.error("failed to get body string of request={}", request);
+        }
+        return sb.toString();
+    }
+
+}
\ No newline at end of file
diff --git 
a/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/utils/InlongRequestWrapper.java
 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/utils/InlongRequestWrapper.java
new file mode 100644
index 000000000..a3f0d4b3b
--- /dev/null
+++ 
b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/utils/InlongRequestWrapper.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.web.utils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+/**
+ * Inlong http request wrapper
+ */
+@Slf4j
+public class InlongRequestWrapper extends HttpServletRequestWrapper {
+
+    private static final ObjectMapper mapper = new ObjectMapper();
+
+    private String bodyParams;
+
+    private Map<String, String[]> params;
+
+    private Map<String, String> headers;
+
+    public InlongRequestWrapper(HttpServletRequest request) {
+        super(request);
+        this.bodyParams = HttpContextUtils.getBodyString(request);
+        this.params = HttpContextUtils.getParameterMap(request);
+        this.headers = HttpContextUtils.getHeaderMapAll(request);
+    }
+
+    @Override
+    public String getParameter(String name) {
+        String result;
+        Object v = params.get(name);
+        if (v == null) {
+            result = null;
+        } else if (v instanceof String[]) {
+            String[] strArr = (String[]) v;
+            if (strArr.length > 0) {
+                result = strArr[0];
+            } else {
+                result = null;
+            }
+        } else if (v instanceof String) {
+            result = (String) v;
+        } else {
+            result = v.toString();
+        }
+        return result;
+    }
+
+    @Override
+    public Map<String, String[]> getParameterMap() {
+        return params;
+    }
+
+    @Override
+    public String[] getParameterValues(String name) {
+        String[] result;
+        Object v = params.get(name);
+        if (v == null) {
+            result = null;
+        } else if (v instanceof String[]) {
+            result = (String[]) v;
+        } else if (v instanceof String) {
+            result = new String[]{(String) v};
+        } else {
+            result = new String[]{v.toString()};
+        }
+        return result;
+    }
+
+    @Override
+    public ServletInputStream getInputStream() {
+        final ByteArrayInputStream inputStream = new 
ByteArrayInputStream(bodyParams.getBytes(StandardCharsets.UTF_8));
+        return new ServletInputStream() {
+
+            @Override
+            public boolean isFinished() {
+                return false;
+            }
+
+            @Override
+            public boolean isReady() {
+                return false;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener) {
+                // no op
+            }
+
+            @Override
+            public int read() {
+                return inputStream.read();
+            }
+        };
+    }
+
+    @Override
+    public BufferedReader getReader() {
+        return new BufferedReader(new 
InputStreamReader(this.getInputStream()));
+    }
+
+    public void addHeader(String name, String value) {
+        headers.put(name, value);
+    }
+
+    public void addBodyParam(String key, String value) throws 
JsonProcessingException {
+        ObjectNode objectNode = (ObjectNode) mapper.readTree(bodyParams);
+        objectNode.put(key, value);
+        bodyParams = objectNode.toString();
+    }
+
+    public void addParameter(String name, String value) {
+        params.put(name, new String[]{value});
+    }
+
+}
diff --git 
a/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/filter/HttpServletRequestFilterTest.java
 
b/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/filter/HttpServletRequestFilterTest.java
new file mode 100644
index 000000000..62d7a1b24
--- /dev/null
+++ 
b/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/filter/HttpServletRequestFilterTest.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.manager.web.filter;
+
+import org.apache.inlong.manager.web.WebBaseTest;
+import org.apache.inlong.manager.web.utils.InlongRequestWrapper;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.mock.web.MockFilterChain;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServlet;
+import java.io.BufferedReader;
+import java.io.IOException;
+
+public class HttpServletRequestFilterTest extends WebBaseTest {
+
+    @Test
+    public void testRepeatableRead() {
+        MockHttpServletRequest req = new MockHttpServletRequest();
+        String bodyStr = "test body str";
+        req.setContent(bodyStr.getBytes());
+        Servlet servlet = new HttpServlet() {
+        };
+        MockHttpServletResponse res = new MockHttpServletResponse();
+        HttpServletRequestFilter filter = new HttpServletRequestFilter();
+        FilterChecker checker = new FilterChecker();
+        MockFilterChain filterChain = new MockFilterChain(servlet, filter, 
checker);
+        Assertions.assertDoesNotThrow(() -> filterChain.doFilter(req, res));
+    }
+
+    class FilterChecker implements Filter {
+
+        @Override
+        public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain)
+                throws IOException, ServletException {
+            Assertions.assertInstanceOf(InlongRequestWrapper.class, request);
+            String first = "";
+            String line;
+            BufferedReader reader = request.getReader();
+            while ((line = reader.readLine()) != null) {
+                first += line;
+            }
+
+            String second = "";
+            BufferedReader reader2 = request.getReader();
+            while ((line = reader2.readLine()) != null) {
+                second += line;
+            }
+
+            Assertions.assertEquals(first, second);
+        }
+    }
+
+}
\ No newline at end of file

Reply via email to