package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.http;
|
|
import com.google.protobuf.ByteString;
|
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
|
import java.io.ByteArrayOutputStream;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.zip.GZIPOutputStream;
|
|
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiHttpService;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.GarminSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.agps.AgpsHandler;
|
|
public class HttpHandler {
|
private static final Logger LOG = LoggerFactory.getLogger(HttpHandler.class);
|
|
private final AgpsHandler agpsHandler;
|
private final ContactsHandler contactsHandler;
|
|
public HttpHandler(GarminSupport deviceSupport) {
|
agpsHandler = new AgpsHandler(deviceSupport);
|
contactsHandler = new ContactsHandler(deviceSupport);
|
}
|
|
public GdiHttpService.HttpService handle(final GdiHttpService.HttpService httpService) {
|
if (httpService.hasRawRequest()) {
|
final GdiHttpService.HttpService.RawResponse rawResponse = handleRawRequest(httpService.getRawRequest());
|
if (rawResponse != null) {
|
return GdiHttpService.HttpService.newBuilder()
|
.setRawResponse(rawResponse)
|
.build();
|
}
|
return null;
|
}
|
|
LOG.warn("Unsupported http service request {}", httpService);
|
|
return null;
|
}
|
|
public GdiHttpService.HttpService.RawResponse handleRawRequest(final GdiHttpService.HttpService.RawRequest rawRequest) {
|
LOG.debug("Got rawRequest: {} - {}", rawRequest.getMethod(), rawRequest.getUrl());
|
|
final GarminHttpRequest request = new GarminHttpRequest(rawRequest);
|
|
final GarminHttpResponse response;
|
if (request.getPath().startsWith("/weather/")) {
|
LOG.info("Got weather request for {}", request.getPath());
|
response = WeatherHandler.handleWeatherRequest(request);
|
} else if (request.getPath().startsWith("/ephemeris/")) {
|
LOG.info("Got AGPS request for {}", request.getPath());
|
response = agpsHandler.handleAgpsRequest(request);
|
} else if (request.getPath().startsWith("/device-gateway/usercontact/")) {
|
LOG.info("Got contacts request for {}", request.getPath());
|
response = contactsHandler.handleRequest(request);
|
} else {
|
LOG.warn("Unhandled path {}", request.getPath());
|
response = null;
|
}
|
|
if (response == null) {
|
return GdiHttpService.HttpService.RawResponse.newBuilder()
|
.setStatus(GdiHttpService.HttpService.Status.UNKNOWN_STATUS)
|
.build();
|
}
|
|
LOG.debug("Http response status={}", response.getStatus());
|
|
return createRawResponse(request, response);
|
}
|
|
private static GdiHttpService.HttpService.RawResponse createRawResponse(
|
final GarminHttpRequest request,
|
final GarminHttpResponse response
|
) {
|
final List<GdiHttpService.HttpService.Header> responseHeaders = new ArrayList<>();
|
for (final Map.Entry<String, String> h : response.getHeaders().entrySet()) {
|
responseHeaders.add(
|
GdiHttpService.HttpService.Header.newBuilder()
|
.setKey(h.getKey())
|
.setValue(h.getValue())
|
.build()
|
);
|
}
|
|
if (response.getStatus() == 200 && request.getRawRequest().hasUseDataXfer() && request.getRawRequest().getUseDataXfer()) {
|
LOG.debug("Data will be returned using data_xfer");
|
int id = DataTransferHandler.registerData(response.getBody());
|
if (response.getOnDataSuccessfullySentListener() != null) {
|
DataTransferHandler.addOnDataSuccessfullySentListener(id, response.getOnDataSuccessfullySentListener());
|
}
|
return GdiHttpService.HttpService.RawResponse.newBuilder()
|
.setStatus(GdiHttpService.HttpService.Status.OK)
|
.setHttpStatus(response.getStatus())
|
.addAllHeader(responseHeaders)
|
.setXferData(
|
GdiHttpService.HttpService.DataTransferItem.newBuilder()
|
.setId(id)
|
.setSize(response.getBody().length)
|
.build()
|
)
|
.build();
|
}
|
|
final byte[] responseBody;
|
if ("gzip".equals(request.getHeaders().get("accept-encoding"))) {
|
LOG.debug("Compressing response");
|
responseHeaders.add(
|
GdiHttpService.HttpService.Header.newBuilder()
|
.setKey("Content-Encoding")
|
.setValue("gzip")
|
.build()
|
);
|
|
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
try (GZIPOutputStream gzos = new GZIPOutputStream(baos)) {
|
gzos.write(response.getBody());
|
gzos.finish();
|
gzos.flush();
|
responseBody = baos.toByteArray();
|
} catch (final Exception e) {
|
LOG.error("Failed to compress response", e);
|
return null;
|
}
|
} else {
|
responseBody = response.getBody();
|
}
|
|
return GdiHttpService.HttpService.RawResponse.newBuilder()
|
.setStatus(response.getStatus() / 100 == 2 ? GdiHttpService.HttpService.Status.OK : GdiHttpService.HttpService.Status.UNKNOWN_STATUS)
|
.setHttpStatus(response.getStatus())
|
.setBody(ByteString.copyFrom(responseBody))
|
.addAllHeader(responseHeaders)
|
.build();
|
}
|
}
|