1 package com.bradmcevoy.http.http11;
2
3 import com.bradmcevoy.http.*;
4 import com.bradmcevoy.http.Request.Method;
5 import com.bradmcevoy.http.exceptions.BadRequestException;
6 import com.bradmcevoy.http.exceptions.ConflictException;
7 import com.bradmcevoy.http.exceptions.NotAuthorizedException;
8 import java.util.Date;
9 import java.util.Map;
10
11 import java.util.regex.Matcher;
12 import java.util.regex.Pattern;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15
16 public class GetHandler implements ExistingEntityHandler {
17
18 private static final Logger log = LoggerFactory.getLogger( GetHandler.class );
19 private final Http11ResponseHandler responseHandler;
20 private final HandlerHelper handlerHelper;
21 private final ResourceHandlerHelper resourceHandlerHelper;
22
23 public GetHandler( Http11ResponseHandler responseHandler, HandlerHelper handlerHelper ) {
24 this.responseHandler = responseHandler;
25 this.handlerHelper = handlerHelper;
26 this.resourceHandlerHelper = new ResourceHandlerHelper( handlerHelper, responseHandler );
27 }
28
29 @Override
30 public void process( HttpManager manager, Request request, Response response ) throws NotAuthorizedException, ConflictException, BadRequestException {
31 log.debug( "process" );
32 this.resourceHandlerHelper.process( manager, request, response, this );
33 }
34
35 @Override
36 public void processResource( HttpManager manager, Request request, Response response, Resource r ) throws NotAuthorizedException, ConflictException, BadRequestException {
37 manager.onGet( request, response, r, request.getParams() );
38 resourceHandlerHelper.processResource( manager, request, response, r, this, true, request.getParams(), null );
39 }
40
41 public void processExistingResource( HttpManager manager, Request request, Response response, Resource resource ) throws NotAuthorizedException, BadRequestException, ConflictException {
42 if( log.isTraceEnabled() ) {
43 log.trace( "process: " + request.getAbsolutePath() );
44 }
45 GetableResource r = (GetableResource) resource;
46 if( checkConditional( r, request ) ) {
47 if( log.isTraceEnabled() ) {
48 log.trace( "respond not modified with: " + responseHandler.getClass().getCanonicalName() );
49 }
50 responseHandler.respondNotModified( r, response, request );
51 return;
52 }
53
54 sendContent( manager, request, response, r, request.getParams() );
55 }
56
57 public Range getRange( Request requestInfo ) {
58
59 String rangeHeader = requestInfo.getRangeHeader();
60 if( rangeHeader == null ) return null;
61 final Matcher matcher = Pattern.compile( "\\s*bytes\\s*=\\s*(\\d+)-(\\d+)" ).matcher( rangeHeader );
62 if( matcher.matches() ) {
63 return new Range( Long.parseLong( matcher.group( 1 ) ), Long.parseLong( matcher.group( 2 ) ) );
64 }
65 return null;
66 }
67
68
69
70 private boolean checkConditional( GetableResource resource, Request request ) {
71
72 if( resource.getMaxAgeSeconds( request.getAuthorization() ) == null ) {
73 log.trace( "resource has null max age, so not modified response is disabled" );
74 return false;
75 }
76 if( checkIfMatch( resource, request ) ) {
77 return true;
78 }
79 if( checkIfModifiedSince( resource, request ) ) {
80 log.trace( "is not modified since" );
81 return true;
82 }
83 if( checkIfNoneMatch( resource, request ) ) {
84 return true;
85 }
86 return false;
87 }
88
89 private boolean checkIfMatch( GetableResource handler, Request requestInfo ) {
90 return false;
91 }
92
93
94
95
96
97
98
99 private boolean checkIfModifiedSince( GetableResource resource, Request requestInfo ) {
100 log.trace( "checkIfModifiedSince" );
101 Long maxAgeSecs = resource.getMaxAgeSeconds( requestInfo.getAuthorization() );
102
103 if( maxAgeSecs == null ) {
104 log.trace( "checkIfModifiedSince: null max age" );
105 return false;
106 } else {
107 log.trace( "checkIfModifiedSince with maxAge" );
108 Date dtRequest = requestInfo.getIfModifiedHeader();
109 if( dtRequest == null ) {
110 log.trace( " no modified date header" );
111 return false;
112 }
113 long timeNow = System.currentTimeMillis();
114 long timeRequest = dtRequest.getTime() + 1000;
115 long timeElapsed = timeNow - timeRequest;
116 if( timeElapsed > maxAgeSecs ) {
117 log.trace( "its been longer then the max age period, so generate fresh response" );
118 return false;
119 } else {
120 Date dtCurrent = resource.getModifiedDate();
121 if( dtCurrent == null ) {
122 if( log.isTraceEnabled() ) {
123 log.trace( "no modified date on resource: " + resource.getClass().getCanonicalName() );
124 }
125 return true;
126 }
127
128 long timeActual = dtCurrent.getTime();
129 boolean unchangedSince = ( timeRequest >= timeActual );
130 if( log.isTraceEnabled() ) {
131 log.trace( "times as long: " + dtCurrent.getTime() + " - " + dtRequest.getTime() );
132 log.trace( "checkModifiedSince: actual: " + dtCurrent + " - request:" + dtRequest + " = " + unchangedSince + " (true indicates no change)" );
133 }
134
135
136 return unchangedSince;
137 }
138 }
139 }
140
141 private boolean checkIfNoneMatch( GetableResource handler, Request requestInfo ) {
142 return false;
143 }
144
145 @Override
146 public String[] getMethods() {
147 return new String[]{Request.Method.GET.code, Request.Method.HEAD.code};
148 }
149
150 @Override
151 public boolean isCompatible( Resource handler ) {
152 return ( handler instanceof GetableResource );
153 }
154
155 private void sendContent( HttpManager manager, Request request, Response response, GetableResource resource, Map<String, String> params ) throws NotAuthorizedException, BadRequestException {
156 try {
157 if( request.getMethod().equals( Method.HEAD ) ) {
158 responseHandler.respondHead( resource, response, request );
159 } else {
160 Range range = getRange( request );
161 if( range != null ) {
162 log.trace( "partial" );
163 responseHandler.respondPartialContent( resource, response, request, params, range );
164 } else {
165 if( log.isTraceEnabled() ) {
166 log.trace( "normal content: " + responseHandler.getClass().getCanonicalName() );
167 }
168 responseHandler.respondContent( resource, response, request, params );
169 }
170 }
171 } catch( NotAuthorizedException notAuthorizedException ) {
172 throw notAuthorizedException;
173 } catch( BadRequestException badRequestException ) {
174 throw badRequestException;
175 } catch( Throwable e ) {
176 log.error( "Exception sending content for:" + request.getAbsolutePath() + " of resource type: " + resource.getClass().getCanonicalName() );
177 throw new RuntimeException( e );
178 }
179 }
180 }