View Javadoc
1   package com.jsql.model.accessible;
2   
3   import com.jsql.model.InjectionModel;
4   import com.jsql.model.bean.util.Header;
5   import com.jsql.model.bean.util.Interaction;
6   import com.jsql.model.bean.util.Request;
7   import com.jsql.util.ConnectionUtil;
8   import com.jsql.util.LogLevelUtil;
9   import org.apache.commons.lang3.StringUtils;
10  import org.apache.logging.log4j.LogManager;
11  import org.apache.logging.log4j.Logger;
12  
13  import java.net.URI;
14  import java.net.http.HttpRequest;
15  import java.net.http.HttpRequest.BodyPublishers;
16  import java.net.http.HttpResponse;
17  import java.net.http.HttpResponse.BodyHandlers;
18  import java.time.Duration;
19  import java.util.AbstractMap.SimpleEntry;
20  import java.util.EnumMap;
21  import java.util.Map;
22  import java.util.Objects;
23  import java.util.Optional;
24  import java.util.concurrent.Callable;
25  import java.util.stream.Stream;
26  
27  /**
28   * Thread unit to test if an administration page exists on the server.
29   * The process can be cancelled by the user.
30   */
31  public class CallableHttpHead implements Callable<CallableHttpHead> {
32      
33      /**
34       * Log4j logger sent to view.
35       */
36      private static final Logger LOGGER = LogManager.getRootLogger();
37      
38      /**
39       * URL to an administration page on the website to get tested.
40       */
41      private final String urlAdminPage;
42      
43      /**
44       * HTTP header response code.
45       */
46      private String responseCodeHttp = StringUtils.EMPTY;
47  
48      private final InjectionModel injectionModel;
49  
50      private final String metadataInjectionProcess;
51      
52      /**
53       * Create a callable to find admin page.
54       * @param urlAdminPage URL of admin page
55       */
56      public CallableHttpHead(String urlAdminPage, InjectionModel injectionModel, String metadataInjectionProcess) {
57          this.urlAdminPage = urlAdminPage;
58          this.injectionModel= injectionModel;
59          this.metadataInjectionProcess= metadataInjectionProcess;
60      }
61  
62      /**
63       * Call URL to an administration page in HEAD mode and send the result back to view.
64       */
65      @Override
66      public CallableHttpHead call() {
67          if (this.injectionModel.getResourceAccess().isSearchAdminStopped()) {
68              return this;
69          }
70          
71          try {
72              var builderHttpRequest = HttpRequest.newBuilder()
73                  .uri(URI.create(this.urlAdminPage))
74                  .method("HEAD", BodyPublishers.noBody())
75                  .timeout(Duration.ofSeconds(4));
76              
77              Stream.of(
78                  this.injectionModel.getMediatorUtils().getParameterUtil().getHeaderFromEntries().split("\\\\r\\\\n")
79              )
80              .map(e -> {
81                  if (e.split(":").length == 2) {
82                      return new SimpleEntry<>(
83                          e.split(":")[0],
84                          e.split(":")[1]
85                      );
86                  } else {
87                      return null;
88                  }
89              })
90              .filter(Objects::nonNull)
91              .forEach(e -> builderHttpRequest.header(e.getKey(), e.getValue()));
92              
93              var httpRequest = builderHttpRequest.build();
94              var httpClient = this.injectionModel.getMediatorUtils().getConnectionUtil().getHttpClient()
95                  .connectTimeout(Duration.ofSeconds(4))
96                  .build();
97              HttpResponse<Void> response = httpClient.send(httpRequest, BodyHandlers.discarding());
98  
99              this.responseCodeHttp = String.valueOf(response.statusCode());
100 
101             Map<Header, Object> msgHeader = new EnumMap<>(Header.class);
102             msgHeader.put(Header.URL, this.urlAdminPage);
103             msgHeader.put(Header.HEADER, ConnectionUtil.getHeadersMap(httpRequest.headers()));
104             msgHeader.put(Header.RESPONSE, ConnectionUtil.getHeadersMap(response));
105             msgHeader.put(Header.METADATA_PROCESS, this.metadataInjectionProcess);
106             
107             var request = new Request();
108             request.setMessage(Interaction.MESSAGE_HEADER);
109             request.setParameters(msgHeader);
110             this.injectionModel.sendToViews(request);
111         } catch (InterruptedException e) {
112             LOGGER.log(LogLevelUtil.IGNORE, e, e);
113             Thread.currentThread().interrupt();
114         } catch (Exception e) {
115             var eMessageImplicit = String.format(
116                 "Problem connecting to %s (implicit reason): %s", 
117                 this.urlAdminPage,
118                 InjectionModel.getImplicitReason(e)
119             );
120             String eMessage = Optional.ofNullable(e.getMessage()).orElse(eMessageImplicit);
121             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, eMessage);
122         }
123         
124         return this;
125     }
126 
127     /**
128      * Check if HTTP response is either 2xx or 3xx, which corresponds to
129      * an acceptable response from the website.
130      * @return true if HTTP code start with 2 or 3
131      */
132     public boolean isHttpResponseOk() {
133         return this.responseCodeHttp.matches("[23]\\d\\d");
134     }
135     
136     
137     // Getters
138     
139     public String getUrl() {
140         return this.urlAdminPage;
141     }
142 }