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