mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-08 16:42:15 +01:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a9c9a7767 | ||
|
|
eb7ce7cef1 | ||
|
|
68fd8dcd76 | ||
|
|
ce8bb2567c | ||
|
|
ab3d9bc120 | ||
|
|
432ec161c1 | ||
|
|
fcaf4a9b51 | ||
|
|
cbb7e6599b | ||
|
|
8f89a144ca | ||
|
|
50bd05b351 | ||
|
|
4e7f5401ec | ||
|
|
3fd56e8c36 | ||
|
|
daf028ab2b | ||
|
|
5467620b32 | ||
|
|
a3cae0f094 | ||
|
|
f74eea4314 | ||
|
|
04e930a766 | ||
|
|
89ac13e805 | ||
|
|
0b86d38517 | ||
|
|
7e76809860 | ||
|
|
4d46b98e7f | ||
|
|
6c1a46aee5 | ||
|
|
a7cef5a1c6 | ||
|
|
8a218a6626 | ||
|
|
542fe18dcd | ||
|
|
25f18ac951 | ||
|
|
5540438595 | ||
|
|
b25456835a | ||
|
|
f86091382f | ||
|
|
dbdf8871cc | ||
|
|
1e6926ee2d | ||
|
|
24cbe98ac2 | ||
|
|
c590b026d6 | ||
|
|
d28221aec9 | ||
|
|
df0c6c8c2d | ||
|
|
876f0f9a14 | ||
|
|
f9f0fc1d67 | ||
|
|
42e357341a | ||
|
|
edc5402aad | ||
|
|
3f61ffa6fb | ||
|
|
1c22b889fe | ||
|
|
e80f5939b2 | ||
|
|
c068088cc1 | ||
|
|
1767f371f7 | ||
|
|
5d5caf64fa | ||
|
|
e095b9419a | ||
|
|
a5ef072f56 | ||
|
|
5f6a2456d4 | ||
|
|
b0f24889f4 | ||
|
|
0a69f0fd51 | ||
|
|
43c0142682 | ||
|
|
1ff16cc54b | ||
|
|
3609cf54c0 | ||
|
|
198038f5ea | ||
|
|
b5a3df85a8 | ||
|
|
6e56c6e0d4 | ||
|
|
9e9b369dc2 |
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -8,7 +8,7 @@ find below useful information about how to contribute to the Gotenberg project.
|
||||
### Install from sources
|
||||
|
||||
1. Install and run the latest version of Docker
|
||||
2. Verify your Go version (>= 1.13)
|
||||
2. Verify your Go version (>= 1.14)
|
||||
3. Fork this repository
|
||||
4. Clone it outside of your `GOPATH` (we're using Go modules)
|
||||
|
||||
|
||||
14
.github/workflows/publish.yml
vendored
14
.github/workflows/publish.yml
vendored
@@ -1,14 +0,0 @@
|
||||
name: Publish
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- releases/*
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish to Docker Hub
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- run: echo $GITHUB_REF
|
||||
#- run: make publish VERSION=$GITHUB_REF DOCKER_USER=${{ secrets.DOCKER_USER }} DOCKER_PASSWORD=${{ secrets.DOCKER_PASSWORD }}
|
||||
12
.github/workflows/push.yml
vendored
12
.github/workflows/push.yml
vendored
@@ -1,12 +0,0 @@
|
||||
name: Push
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: Lint, tests and code coverage
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
#- run: make lint
|
||||
#- run: make tests CODE_COVERAGE=1
|
||||
#- run: bash <(curl -s https://codecov.io/bash) -t ${{ secrets.CODECOV_TOKEN }}
|
||||
26
.github/workflows/tests_maybe_release.yml
vendored
Normal file
26
.github/workflows/tests_maybe_release.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: tests_maybe_release
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
tests_maybe_release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- uses: actions/checkout@v1
|
||||
- name: Lint code
|
||||
run: make lint
|
||||
- name: Run tests
|
||||
run: |
|
||||
make tests CODE_COVERAGE=1
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
- name: Release
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
run: make publish VERSION=${{ github.event.release.tag_name }} DOCKER_USER=${{ secrets.DOCKER_USER }} DOCKER_PASSWORD=${{ secrets.DOCKER_PASSWORD }}
|
||||
26
.travis.yml
26
.travis.yml
@@ -1,26 +0,0 @@
|
||||
sudo: required
|
||||
|
||||
language: generic
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: d6pliM7iR7KJ3TQkr1C0tHi0HgU6Vdmc/ycw11XrXs794/dgj6g9UDrhgcvT2mTzOVIUNouHx7gyEWAlwJv7p8PPyguHJfIsyqMWfaXNPoytTx1ETUiygl1G/UsvXVdry6I5tZF/U+/PJ3hBXoAvo8EOFe0/MxxvP3ghCeeCpeEwEdoYP2jbADGffywVUNI7OEdmS29A28GusXXp2cWCIZYSq5Gn5iu1ZMPaJA6SkRTXpS+iVVLUvlbz5HW09ETFfurTvsdz5Ze4JICiuQt///CR1uwdxD8K7Ils/mkenaMtja9NHA9RdQBa51Azn8iCLsObCTYc52Zb6atbCi/X4ae9M8GA8qaaLigNz5G4v1BHneJylYfWKj5GwqUA3VmRu1mlEw7d2sN2uFRmgIl5kgsYYyOVOLBOKaJWhyBhNnR4U8KeqwUkOnlSdmNZnjfexXXBEcKHen1SozpXwMnzZh8LZuN6BNYd6TVpKmjulGI3vqNMM0c4JJZ9pSm4q5FjbNGQArwCsujDDwY4bCGZSJJTPMXjYOrx4yJ1RY+0TpyV9oDU3ogEqaWnhrkgrphfiYBlDY2bEvrxMTMukLCxJb0Nru6LGCpg4X1P9hu9r0gceqUSnBgdJI4rYTNddenxlEd4j/Thqv835stJWz6YoV+rfvERuSUpntl8xvrk3U8=
|
||||
- secure: CmLh169xwt3OC7l19lDUwdZYfw+l/+XXKjTGxnuJiXHa9hAH+nc4mEUSmqHMHwjquyYE6LnSVGZ94LH8sCaGed/TMm0Lj3DZtZ0VsjYu3sKsNrVJn5WdYEah+GvNJ8i8uzvHnGk1L2fAagLpXFUB2K9UraA1CFiHs1fF5Fua7Ra0mE7lMz0MFvyvzcmc9u8nMz71K2YVsXqn+I/rv8onJCTtc/Ds0hVrBXwG5Fh0T3xHqjOhME9ZI2hRHnnQVdBojSY3USifQ//qAKowfBVc0pebEtgFpyXx/I17A6xCm0KVtnA2tNqu1+XFkjWaBzryaLE9ujhJcTRC/YK0JUZ+QxfYbD5C7jVy9Jlx1lOEjJ42B/ImNxPP+9p3wi2MWNbcbZJPxIe635fnT17lI7CLK2Qg1xjfTQ4WTEKW5IhnYMiyfRKiripFh4PCkDm8cJlTbpntsX1n0uheydbsgf/11vS7o1WGhVQ8+Jelc4DvIbBHCqienQEOLJDBwm7FiK5JbwZJ6ZAGeDM/IhGU1h9PNjVbHUyJhUxYoPYUE9QsZFT7ENCrRQpq49KOzXBRfffyJNJRh+Ep9X5YoW0dUp0MNu5B7z2+6w9X9n/C+loa11xF42bFzniCvvbSOQ37J+EngDinVxJkNPeyivR4fye2ENhIAjAEjouTJLOSXL9nAOU=
|
||||
|
||||
stages:
|
||||
- tests
|
||||
- publish
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: tests
|
||||
script:
|
||||
- make lint
|
||||
- make tests CODE_COVERAGE=1
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
- stage: publish
|
||||
if: tag IS present
|
||||
script: make publish VERSION=$TRAVIS_TAG DOCKER_USER=$DOCKER_USER DOCKER_PASSWORD=$DOCKER_PASS
|
||||
10
Makefile
10
Makefile
@@ -1,13 +1,13 @@
|
||||
GOLANG_VERSION=1.13
|
||||
GOLANG_VERSION=1.14
|
||||
VERSION=snapshot
|
||||
DOCKER_USER=
|
||||
DOCKER_PASSWORD=
|
||||
DOCKER_REGISTRY=thecodingmachine
|
||||
GOTENBERG_USER_GID=1001
|
||||
GOTENBERG_USER_UID=1001
|
||||
GOLANGCI_LINT_VERSION=1.20.1
|
||||
GOLANGCI_LINT_VERSION=1.27.0
|
||||
CODE_COVERAGE=0
|
||||
TINI_VERSION=0.18.0
|
||||
TINI_VERSION=0.19.0
|
||||
MAXIMUM_WAIT_TIMEOUT=30.0
|
||||
MAXIMUM_WAIT_DELAY=10.0
|
||||
MAXIMUM_WEBHOOK_URL_TIMEOUT=30.0
|
||||
@@ -19,6 +19,7 @@ DISABLE_UNOCONV=0
|
||||
LOG_LEVEL=INFO
|
||||
ROOT_PATH=/
|
||||
DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE=1048576
|
||||
GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS=0
|
||||
|
||||
# build the base Docker image.
|
||||
base:
|
||||
@@ -36,7 +37,6 @@ fmt:
|
||||
|
||||
# run all linters.
|
||||
lint:
|
||||
make workspace
|
||||
docker build --build-arg GOLANGCI_LINT_VERSION=$(GOLANGCI_LINT_VERSION) -t $(DOCKER_REGISTRY)/gotenberg:lint -f build/lint/Dockerfile .
|
||||
docker run --rm $(DOCKER_REGISTRY)/gotenberg:lint
|
||||
|
||||
@@ -58,7 +58,7 @@ image:
|
||||
|
||||
# start the API using previously built Docker image.
|
||||
gotenberg:
|
||||
docker run -it --rm -e MAXIMUM_WAIT_TIMEOUT=$(MAXIMUM_WAIT_TIMEOUT) -e MAXIMUM_WAIT_DELAY=$(MAXIMUM_WAIT_DELAY) -e MAXIMUM_WEBHOOK_URL_TIMEOUT=$(MAXIMUM_WEBHOOK_URL_TIMEOUT) -e DEFAULT_WEBHOOK_URL_TIMEOUT=$(DEFAULT_WEBHOOK_URL_TIMEOUT) -e MAXIMUM_WEBHOOK_URL_TIMEOUT=$(MAXIMUM_WEBHOOK_URL_TIMEOUT) -e DEFAULT_LISTEN_PORT=$(DEFAULT_LISTEN_PORT) -e DISABLE_GOOGLE_CHROME=$(DISABLE_GOOGLE_CHROME) -e DISABLE_UNOCONV=$(DISABLE_UNOCONV) -e LOG_LEVEL=$(LOG_LEVEL) -e ROOT_PATH=$(ROOT_PATH) -e DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE=$(DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE) -p "$(DEFAULT_LISTEN_PORT):$(DEFAULT_LISTEN_PORT)" $(DOCKER_REGISTRY)/gotenberg:$(VERSION)
|
||||
docker run -it --rm -e MAXIMUM_WAIT_TIMEOUT=$(MAXIMUM_WAIT_TIMEOUT) -e MAXIMUM_WAIT_DELAY=$(MAXIMUM_WAIT_DELAY) -e MAXIMUM_WEBHOOK_URL_TIMEOUT=$(MAXIMUM_WEBHOOK_URL_TIMEOUT) -e DEFAULT_WEBHOOK_URL_TIMEOUT=$(DEFAULT_WEBHOOK_URL_TIMEOUT) -e MAXIMUM_WEBHOOK_URL_TIMEOUT=$(MAXIMUM_WEBHOOK_URL_TIMEOUT) -e DEFAULT_LISTEN_PORT=$(DEFAULT_LISTEN_PORT) -e DISABLE_GOOGLE_CHROME=$(DISABLE_GOOGLE_CHROME) -e DISABLE_UNOCONV=$(DISABLE_UNOCONV) -e LOG_LEVEL=$(LOG_LEVEL) -e ROOT_PATH=$(ROOT_PATH) -e DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE=$(DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE) -e GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS=$(GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS) -p "$(DEFAULT_LISTEN_PORT):$(DEFAULT_LISTEN_PORT)" $(DOCKER_REGISTRY)/gotenberg:$(VERSION)
|
||||
|
||||
# publish Gotenberg images according to version.
|
||||
publish:
|
||||
|
||||
@@ -13,7 +13,7 @@ At TheCodingMachine, we build a lot of web applications (intranets, extranets an
|
||||
|
||||
* HTML and Markdown conversions using Google Chrome headless
|
||||
* Office conversions (.txt, .rtf, .docx, .doc, .odt, .pptx, .ppt, .odp and so on) using [unoconv](https://github.com/dagwieers/unoconv)
|
||||
* Assets :package:: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs!
|
||||
* Assets :package:: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beautiful PDFs!
|
||||
* Easily interact with the API using our [Go](https://github.com/thecodingmachine/gotenberg-go-client) and [PHP](https://github.com/thecodingmachine/gotenberg-php-client) libraries
|
||||
|
||||
## Quick start
|
||||
@@ -31,8 +31,9 @@ to learn how to interact with it!
|
||||
|
||||
## Badges
|
||||
|
||||
[](https://hub.docker.com/r/thecodingmachine/gotenberg)
|
||||
[](https://microbadger.com/images/thecodingmachine/gotenberg:6)
|
||||
[](https://travis-ci.org/thecodingmachine/gotenberg)
|
||||
[](https://github.com/thecodingmachine/gotenberg/workflows/tests_maybe_release)
|
||||
[](https://godoc.org/github.com/thecodingmachine/gotenberg)
|
||||
[](https://codecov.io/gh/thecodingmachine/gotenberg)
|
||||
[](https://goreportcard.com/report/thecodingmachine/gotenberg)
|
||||
|
||||
@@ -58,7 +58,10 @@ RUN curl -Ls $UNO_URL -o /usr/bin/unoconv &&\
|
||||
# | https://github.com/thecodingmachine/gotenberg/issues/29
|
||||
# |
|
||||
|
||||
RUN apt-get -y install pdftk
|
||||
ARG PDFTK_VERSION=924565150
|
||||
|
||||
RUN wget -O /usr/bin/pdftk "https://gitlab.com/pdftk-java/pdftk/-/jobs/${PDFTK_VERSION}/artifacts/raw/build/native-image/pdftk" \
|
||||
&& chmod a+x /usr/bin/pdftk
|
||||
|
||||
# |--------------------------------------------------------------------------
|
||||
# | Fonts
|
||||
|
||||
@@ -4,6 +4,8 @@ title: Install
|
||||
|
||||
Gotenberg is shipped within a Docker image.
|
||||
|
||||
**[Gotenberg should ONLY be used in a trusted network by trusted applications. Do NOT expose Gotenberg to the external world.](https://blazej-adamczyk.medium.com/0-day-bug-breaks-multi-million-dollar-system-38c9e31b27e9)**
|
||||
|
||||
You may start it with:
|
||||
|
||||
```bash
|
||||
@@ -24,7 +26,7 @@ For instance:
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/thecodingmachine/gotenberg.git
|
||||
$ make publish GOTENBERG_USER_GID=your_custom_gid GOTENBERG_USER_UID=your_custom_uid DOCKER_REGISTRY=your_registry DOCKER_USER=registry_user DOCKER_PASSWORD=registry_password VERSION=6.1.0
|
||||
$ make publish GOTENBERG_USER_GID=your_custom_gid GOTENBERG_USER_UID=your_custom_uid DOCKER_REGISTRY=your_registry DOCKER_USER=registry_user DOCKER_PASSWORD=registry_password VERSION=version
|
||||
```
|
||||
|
||||
> `master` branch is always up-to-date with the latest version of the API.
|
||||
@@ -38,7 +40,7 @@ version: '3'
|
||||
|
||||
services:
|
||||
|
||||
# your others services
|
||||
# your other services
|
||||
|
||||
gotenberg:
|
||||
image: thecodingmachine/gotenberg:6
|
||||
@@ -65,6 +67,7 @@ securityContext:
|
||||
## Cloud Run (Google Cloud)
|
||||
|
||||
If you're looking for cost savings, you might be interested by [Cloud Run](https://cloud.google.com/run).
|
||||
However, according to some users, doing asynchronous conversion (with a webhook) might not working.
|
||||
|
||||
In the following examples, we will assume your
|
||||
Gotenberg API is available at [http://localhost:3000](http://localhost:3000).
|
||||
|
||||
@@ -58,6 +58,14 @@ The hard limit is 100 MB and is defined by Google Chrome itself.
|
||||
> The default Google Chrome rpcc buffer size may also be overridden per request thanks to the form field `googleChromeRpccBufferSize`.
|
||||
> See the [rpcc buffer size section](#html.rpcc_buffer_size).
|
||||
|
||||
## Google Chrome ignore certificate errors
|
||||
|
||||
When performing a [URL](#url) conversion, Google Chrome will not accept certificate errors.
|
||||
|
||||
You may allow insecure connections by setting the `GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS` environment variable to `"1"`.
|
||||
|
||||
**You should be careful with this feature and only enable it in your development environment.**
|
||||
|
||||
## Disable LibreOffice (unoconv)
|
||||
|
||||
You may also disable LibreOffice (unoconv) with `DISABLE_UNOCONV`.
|
||||
|
||||
@@ -157,7 +157,7 @@ You may also send additional files. For instance: images, fonts, stylesheets and
|
||||
The only requirement is to make sure that their paths
|
||||
are on the same level as the `index.html` file.
|
||||
|
||||
In others words, this will work:
|
||||
In other words, this will work:
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
@@ -243,11 +243,11 @@ $dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
```
|
||||
|
||||
## Paper size, margins, orientation
|
||||
## Paper size, margins, orientation, scaling
|
||||
|
||||
You may also customize the resulting PDF format.
|
||||
|
||||
By default, it will be rendered with `A4` size, `1 inch` margins and `portrait` orientation.
|
||||
By default, it will be rendered with `A4` size, `1 inch` margins and `portrait` orientation and 100% (`1.0`) page scale.
|
||||
|
||||
> Paper size and margins have to be provided in `inches`. Same for margins.
|
||||
|
||||
@@ -265,6 +265,7 @@ $ curl --request POST \
|
||||
--form marginLeft=0 \
|
||||
--form marginRight=0 \
|
||||
--form landscape=true \
|
||||
--form scale=0.75 \
|
||||
-o result.pdf
|
||||
```
|
||||
|
||||
@@ -279,6 +280,7 @@ req := gotenberg.NewHTMLRequest(index)
|
||||
req.PaperSize(gotenberg.A4)
|
||||
req.Margins(gotenberg.NoMargins)
|
||||
req.Landscape(true)
|
||||
req.Scale(0.75)
|
||||
dest := "result.pdf"
|
||||
c.Store(req, dest)
|
||||
```
|
||||
@@ -297,6 +299,7 @@ $request = new HTMLRequest($index);
|
||||
$request->setPaperSize(Request::A4);
|
||||
$request->setMargins(Request::NO_MARGINS);
|
||||
$request->setLandscape(true);
|
||||
$request->setScale(0.75);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
```
|
||||
|
||||
@@ -14,6 +14,9 @@ named `remoteURL` instead. Otherwise, URL conversions work the same as HTML conv
|
||||
> **Attention:** when converting a website to PDF, you should remove all margins.
|
||||
> If not, some of the content of the page might be hidden.
|
||||
|
||||
> **Attention:** if you try to convert a URL from a Docker Compose service named `app` (i.e. `removeURL` = `http://app/an/entrypoint`),
|
||||
> the resulting PDF will be blank. Make sure to rename your service to avoid this issue.
|
||||
|
||||
### cURL
|
||||
|
||||
```bash
|
||||
|
||||
@@ -37,7 +37,7 @@ version: '3'
|
||||
|
||||
services:
|
||||
|
||||
# your others services
|
||||
# your other services
|
||||
|
||||
gotenberg:
|
||||
image: thecodingmachine/gotenberg:6
|
||||
|
||||
@@ -8,4 +8,5 @@ title: Links
|
||||
|
||||
* Follow the progress on the [GitHub repository](https://github.com/thecodingmachine/gotenberg)
|
||||
* Follow [@gulnap](https://twitter.com/gulnap) on Twitter
|
||||
* Thanks to [@mafredri](https://github.com/mafredri) for its help and its wonderful [cdp](https://github.com/mafredri/cdp) library
|
||||
* Thanks to [@mafredri](https://github.com/mafredri) for his help and his wonderful [cdp](https://github.com/mafredri/cdp) library
|
||||
* OpenAPI documentation for the API can be found [on GitHub](https://github.com/thecodingmachine/gotenberg/blob/master/docs/openapi.yaml)
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
FROM thecodingmachine/gotenberg:workspace
|
||||
|
||||
# |--------------------------------------------------------------------------
|
||||
# | GolangCI-Lint
|
||||
# |--------------------------------------------------------------------------
|
||||
# |
|
||||
# | Installs GolangCI-Lint, a linters Runner for Go. 5x faster
|
||||
# | than gometalinter.
|
||||
# |
|
||||
|
||||
ARG GOLANGCI_LINT_VERSION
|
||||
|
||||
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b /usr/local/bin v${GOLANGCI_LINT_VERSION} &&\
|
||||
golangci-lint --version
|
||||
FROM golangci/golangci-lint:v$GOLANGCI_LINT_VERSION
|
||||
|
||||
# |--------------------------------------------------------------------------
|
||||
# | Final touch
|
||||
@@ -21,16 +10,13 @@ RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.s
|
||||
# |
|
||||
|
||||
# Define our working directory outside of $GOPATH (we're using go modules).
|
||||
USER gotenberg
|
||||
WORKDIR /gotenberg/lint
|
||||
|
||||
# Install module dependencies.
|
||||
COPY --chown=gotenberg:gotenberg go.mod go.sum ./
|
||||
# Copy our code source.
|
||||
COPY . .
|
||||
|
||||
# Install module dependencies.
|
||||
RUN go mod download &&\
|
||||
go mod verify
|
||||
|
||||
# Copy our code source.
|
||||
COPY --chown=gotenberg:gotenberg . .
|
||||
|
||||
CMD ["golangci-lint", "run" ,"--tests=false", "--enable-all", "--disable=dupl", "--disable=funlen", "--disable=wsl", "--disable=gocognit" ]
|
||||
CMD ["golangci-lint", "run" ,"--tests=false", "--enable-all", "--disable=dupl", "--disable=funlen", "--disable=wsl", "--disable=gocognit", "--disable=gomnd", "--disable=goimports" ]
|
||||
@@ -10,7 +10,7 @@ FROM thecodingmachine/gotenberg:workspace AS workspace
|
||||
ARG VERSION
|
||||
|
||||
ENV GOOS=linux \
|
||||
GOARCH=amd64 \
|
||||
GOARCH=amd64 \
|
||||
CGO_ENABLED=0
|
||||
|
||||
# Define our workding outside of $GOPATH (we're using go modules).
|
||||
@@ -42,7 +42,7 @@ LABEL authors="Julien Neuhart <j.neuhart@thecodingmachine.com>"
|
||||
|
||||
ARG TINI_VERSION
|
||||
|
||||
ADD --chown=gotenberg https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-static /tini
|
||||
ADD https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-static /tini
|
||||
RUN chmod +x /tini
|
||||
ENTRYPOINT [ "/tini", "--" ]
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -24,11 +25,11 @@ func main() {
|
||||
if err != nil {
|
||||
systemLogger.FatalOp(op, err)
|
||||
}
|
||||
systemLogger.InfofOp(op, "Gotenberg %s", version)
|
||||
systemLogger.DebugfOp(op, "configuration: %+v", config)
|
||||
systemLogger.InfoOpf(op, "Gotenberg %s", version)
|
||||
systemLogger.DebugOpf(op, "configuration: %+v", config)
|
||||
if !config.DisableGoogleChrome() {
|
||||
// start Google Chrome headless.
|
||||
if err := chrome.Start(systemLogger); err != nil {
|
||||
if err := chrome.Start(systemLogger, config.GoogleChromeIgnoreCertificateErrors()); err != nil {
|
||||
systemLogger.FatalOp(op, err)
|
||||
}
|
||||
}
|
||||
@@ -36,9 +37,9 @@ func main() {
|
||||
srv := xhttp.New(config)
|
||||
// run our API in a goroutine so that it doesn't block.
|
||||
go func() {
|
||||
systemLogger.InfofOp(op, "http server started on port '%d'", config.DefaultListenPort())
|
||||
systemLogger.InfoOpf(op, "http server started on port '%d'", config.DefaultListenPort())
|
||||
if err := srv.Start(fmt.Sprintf(":%d", config.DefaultListenPort())); err != nil {
|
||||
if err != http.ErrServerClosed {
|
||||
if errors.Is(err, http.ErrServerClosed) {
|
||||
systemLogger.FatalOp(op, err)
|
||||
}
|
||||
}
|
||||
|
||||
440
docs/index.html
440
docs/index.html
@@ -132,6 +132,8 @@
|
||||
</a>Install</h1>
|
||||
<p>Gotenberg is shipped within a Docker image.</p>
|
||||
|
||||
<p><strong><a href="https://blazej-adamczyk.medium.com/0-day-bug-breaks-multi-million-dollar-system-38c9e31b27e9">Gotenberg should ONLY be used in a trusted network by trusted applications. Do NOT expose Gotenberg to the external world.</a></strong></p>
|
||||
|
||||
<p>You may start it with:</p>
|
||||
|
||||
<pre class="chroma">$ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:6
|
||||
@@ -154,7 +156,7 @@
|
||||
<p>For instance:</p>
|
||||
|
||||
<pre class="chroma">$ git clone https://github.com/thecodingmachine/gotenberg.git
|
||||
$ make publish <span class="nv">GOTENBERG_USER_GID</span><span class="o">=</span>your_custom_gid <span class="nv">GOTENBERG_USER_UID</span><span class="o">=</span>your_custom_uid <span class="nv">DOCKER_REGISTRY</span><span class="o">=</span>your_registry <span class="nv">DOCKER_USER</span><span class="o">=</span>registry_user <span class="nv">DOCKER_PASSWORD</span><span class="o">=</span>registry_password <span class="nv">VERSION</span><span class="o">=</span>6.1.0
|
||||
$ make publish <span class="nv">GOTENBERG_USER_GID</span><span class="o">=</span>your_custom_gid <span class="nv">GOTENBERG_USER_UID</span><span class="o">=</span>your_custom_uid <span class="nv">DOCKER_REGISTRY</span><span class="o">=</span>your_registry <span class="nv">DOCKER_USER</span><span class="o">=</span>registry_user <span class="nv">DOCKER_PASSWORD</span><span class="o">=</span>registry_password <span class="nv">VERSION</span><span class="o">=</span>version
|
||||
</pre>
|
||||
|
||||
<blockquote>
|
||||
@@ -167,14 +169,14 @@ $ make publish <span class="nv">GOTENBERG_USER_GID</span><span class="o">=</span
|
||||
|
||||
<p>You may also add it in your Docker Compose stack:</p>
|
||||
|
||||
<pre class="chroma"><span class="k">version</span><span class="p">:</span><span class="w"> </span><span class="s1">'3'</span><span class="w">
|
||||
<pre class="chroma"><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s1">'3'</span><span class="w">
|
||||
</span><span class="w">
|
||||
</span><span class="w"></span><span class="k">services</span><span class="p">:</span><span class="w">
|
||||
</span><span class="w"></span><span class="nt">services</span><span class="p">:</span><span class="w">
|
||||
</span><span class="w">
|
||||
</span><span class="w"> </span><span class="c"># your others services</span><span class="w">
|
||||
</span><span class="w"> </span><span class="c"># your other services</span><span class="w">
|
||||
</span><span class="w">
|
||||
</span><span class="w"> </span><span class="k">gotenberg</span><span class="p">:</span><span class="w">
|
||||
</span><span class="w"> </span><span class="k">image</span><span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">6</span><span class="w">
|
||||
</span><span class="w"> </span><span class="nt">gotenberg</span><span class="p">:</span><span class="w">
|
||||
</span><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">thecodingmachine/gotenberg:6</span><span class="w">
|
||||
</span></pre>
|
||||
|
||||
<blockquote>
|
||||
@@ -204,7 +206,8 @@ $ make publish <span class="nv">GOTENBERG_USER_GID</span><span class="o">=</span
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>Cloud Run (Google Cloud)</h2>
|
||||
|
||||
<p>If you’re looking for cost savings, you might be interested by <a href="https://cloud.google.com/run">Cloud Run</a>.</p>
|
||||
<p>If you’re looking for cost savings, you might be interested by <a href="https://cloud.google.com/run">Cloud Run</a>.
|
||||
However, according to some users, doing asynchronous conversion (with a webhook) might not working.</p>
|
||||
|
||||
<p>In the following examples, we will assume your
|
||||
Gotenberg API is available at <a href="http://localhost:3000">http://localhost:3000</a>.</p>
|
||||
@@ -331,6 +334,16 @@ The hard limit is 100 MB and is defined by Google Chrome itself.</p>
|
||||
See the <a href="#html.rpcc_buffer_size">rpcc buffer size section</a>.</p>
|
||||
</blockquote>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="environment_variables.google_chrome_ignore_certificate_errors" href="#environment_variables.google_chrome_ignore_certificate_errors">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>Google Chrome ignore certificate errors</h2>
|
||||
|
||||
<p>When performing a <a href="#url">URL</a> conversion, Google Chrome will not accept certificate errors.</p>
|
||||
|
||||
<p>You may allow insecure connections by setting the <code>GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS</code> environment variable to <code>"1"</code>.</p>
|
||||
|
||||
<p><strong>You should be careful with this feature and only enable it in your development environment.</strong></p>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="environment_variables.disable_libre_office_unoconv" href="#environment_variables.disable_libre_office_unoconv">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>Disable LibreOffice (unoconv)</h2>
|
||||
@@ -470,15 +483,15 @@ which will be converted to PDF.</p>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$request = new HTMLRequest($index);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer" href="#html.header_and_footer">
|
||||
@@ -562,19 +575,19 @@ Respectively, a file named <code>header.html</code> and <code>footer.html</code>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$header = DocumentFactory::makeFromPath('header.html', '/path/to/file');
|
||||
$footer = DocumentFactory::makeFromPath('footer.html', '/path/to/file');
|
||||
$request = new HTMLRequest($index);
|
||||
$request->setHeader($header);
|
||||
$request->setFooter($footer);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$header</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'header.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$footer</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'footer.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setHeader</span><span class="p">(</span><span class="nv">$header</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setFooter</span><span class="p">(</span><span class="nv">$footer</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets" href="#html.assets">
|
||||
@@ -586,7 +599,7 @@ $client->store($request, $dest);
|
||||
<p>The only requirement is to make sure that their paths
|
||||
are on the same level as the <code>index.html</code> file.</p>
|
||||
|
||||
<p>In others words, this will work:</p>
|
||||
<p>In other words, this will work:</p>
|
||||
|
||||
<pre class="chroma"><span class="cp"><!doctype html></span>
|
||||
<span class="p"><</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p">></span>
|
||||
@@ -658,36 +671,36 @@ see to the <a href="#fonts">fonts section</a>.</p>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$assets = [
|
||||
DocumentFactory::makeFromPath('style.css', '/path/to/file'),
|
||||
DocumentFactory::makeFromPath('img.png', '/path/to/file'),
|
||||
DocumentFactory::makeFromPath('font.woff', '/path/to/file'),
|
||||
];
|
||||
$request = new HTMLRequest($index);
|
||||
$request->setAssets($assets);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$assets</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'style.css'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">),</span>
|
||||
<span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'img.png'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">),</span>
|
||||
<span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'font.woff'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">),</span>
|
||||
<span class="p">];</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setAssets</span><span class="p">(</span><span class="nv">$assets</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation" href="#html.paper_size_margins_orientation">
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation_scaling" href="#html.paper_size_margins_orientation_scaling">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>Paper size, margins, orientation</h2>
|
||||
</a>Paper size, margins, orientation, scaling</h2>
|
||||
|
||||
<p>You may also customize the resulting PDF format.</p>
|
||||
|
||||
<p>By default, it will be rendered with <code>A4</code> size, <code>1 inch</code> margins and <code>portrait</code> orientation.</p>
|
||||
<p>By default, it will be rendered with <code>A4</code> size, <code>1 inch</code> margins and <code>portrait</code> orientation and 100% (<code>1.0</code>) page scale.</p>
|
||||
|
||||
<blockquote>
|
||||
<p>Paper size and margins have to be provided in <code>inches</code>. Same for margins.</p>
|
||||
</blockquote>
|
||||
|
||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation.c_url" href="#html.paper_size_margins_orientation.c_url">
|
||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation_scaling.c_url" href="#html.paper_size_margins_orientation_scaling.c_url">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>cURL</h3>
|
||||
|
||||
@@ -702,10 +715,11 @@ $client->store($request, $dest);
|
||||
</span><span class="se"></span> --form <span class="nv">marginLeft</span><span class="o">=</span><span class="m">0</span> <span class="se">\
|
||||
</span><span class="se"></span> --form <span class="nv">marginRight</span><span class="o">=</span><span class="m">0</span> <span class="se">\
|
||||
</span><span class="se"></span> --form <span class="nv">landscape</span><span class="o">=</span><span class="nb">true</span> <span class="se">\
|
||||
</span><span class="se"></span> --form <span class="nv">scale</span><span class="o">=</span>0.75 <span class="se">\
|
||||
</span><span class="se"></span> -o result.pdf
|
||||
</pre>
|
||||
|
||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation.go" href="#html.paper_size_margins_orientation.go">
|
||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation_scaling.go" href="#html.paper_size_margins_orientation_scaling.go">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>Go</h3>
|
||||
|
||||
@@ -717,27 +731,29 @@ $client->store($request, $dest);
|
||||
<span class="nx">req</span><span class="p">.</span><span class="nf">PaperSize</span><span class="p">(</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">A4</span><span class="p">)</span>
|
||||
<span class="nx">req</span><span class="p">.</span><span class="nf">Margins</span><span class="p">(</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NoMargins</span><span class="p">)</span>
|
||||
<span class="nx">req</span><span class="p">.</span><span class="nf">Landscape</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
|
||||
<span class="nx">req</span><span class="p">.</span><span class="nf">Scale</span><span class="p">(</span><span class="mf">0.75</span><span class="p">)</span>
|
||||
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">"result.pdf"</span>
|
||||
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
||||
</pre>
|
||||
|
||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation.php" href="#html.paper_size_margins_orientation.php">
|
||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation_scaling.php" href="#html.paper_size_margins_orientation_scaling.php">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
use TheCodingMachine\Gotenberg\Request;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Request</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$request = new HTMLRequest($index);
|
||||
$request->setPaperSize(Request::A4);
|
||||
$request->setMargins(Request::NO_MARGINS);
|
||||
$request->setLandscape(true);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setPaperSize</span><span class="p">(</span><span class="nx">Request</span><span class="o">::</span><span class="na">A4</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setMargins</span><span class="p">(</span><span class="nx">Request</span><span class="o">::</span><span class="na">NO_MARGINS</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setLandscape</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setScale</span><span class="p">(</span><span class="mf">0.75</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.page_ranges" href="#html.page_ranges">
|
||||
@@ -779,17 +795,17 @@ of Google Chrome, e.g. <code>1-5,8,11-13</code>.</p>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
use TheCodingMachine\Gotenberg\Request;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Request</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$request = new HTMLRequest($index);
|
||||
$request->setPageRanges('1-3,5');
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setPageRanges</span><span class="p">(</span><span class="s1">'1-3,5'</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.wait_delay" href="#html.wait_delay">
|
||||
@@ -834,17 +850,17 @@ a lot on JavaScript for rendering.</p>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
use TheCodingMachine\Gotenberg\Request;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Request</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$request = new HTMLRequest($index);
|
||||
$request->setWaitDelay(5.5);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setWaitDelay</span><span class="p">(</span><span class="mf">5.5</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.rpcc_buffer_size" href="#html.rpcc_buffer_size">
|
||||
@@ -892,17 +908,17 @@ The hard limit is 100 MB and is defined by Google Chrome itself.</p>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
use TheCodingMachine\Gotenberg\Request;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Request</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$request = new HTMLRequest($index);
|
||||
$request->setGoogleChromeRpccBufferSize(1048576);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setGoogleChromeRpccBufferSize</span><span class="p">(</span><span class="mi">1048576</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
@@ -925,6 +941,9 @@ named <code>remoteURL</code> instead. Otherwise, URL conversions work the same a
|
||||
<blockquote>
|
||||
<p><strong>Attention:</strong> when converting a website to PDF, you should remove all margins.
|
||||
If not, some of the content of the page might be hidden.</p>
|
||||
|
||||
<p><strong>Attention:</strong> if you try to convert a URL from a Docker Compose service named <code>app</code> (i.e. <code>removeURL</code> = <code>http://app/an/entrypoint</code>),
|
||||
the resulting PDF will be blank. Make sure to rename your service to avoid this issue.</p>
|
||||
</blockquote>
|
||||
|
||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="url.basic.c_url" href="#url.basic.c_url">
|
||||
@@ -959,14 +978,14 @@ If not, some of the content of the page might be hidden.</p>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\URLRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\URLRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$request = new URLRequest('https://google.com');
|
||||
$request->setMargins(Request::NO_MARGINS);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">URLRequest</span><span class="p">(</span><span class="s1">'https://google.com'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setMargins</span><span class="p">(</span><span class="nx">Request</span><span class="o">::</span><span class="na">NO_MARGINS</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="url.custom_http_headers" href="#url.custom_http_headers">
|
||||
@@ -1015,14 +1034,14 @@ canonical key for <code>accept-encoding</code> is <code>Accept-Encoding</code>.<
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\URLRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\URLRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$request = new URLRequest('https://google.com');
|
||||
$request->addRemoteURLHTTPHeader('Your-Header', 'Foo')
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">URLRequest</span><span class="p">(</span><span class="s1">'https://google.com'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">addRemoteURLHTTPHeader</span><span class="p">(</span><span class="s1">'Your-Header'</span><span class="p">,</span> <span class="s1">'Foo'</span><span class="p">)</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
@@ -1088,18 +1107,18 @@ in the file <code>index.html</code>. This function will convert a given markdown
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\MarkdownRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\MarkdownRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$markdowns = [
|
||||
DocumentFactory::makeFromPath('file.md', '/path/to/file'),
|
||||
];
|
||||
$request = new MarkdownRequest($index, $markdowns);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$markdowns</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'file.md'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">),</span>
|
||||
<span class="p">];</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MarkdownRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">,</span> <span class="nv">$markdowns</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
@@ -1169,18 +1188,18 @@ $client->store($request, $dest);
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\OfficeRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\OfficeRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$files = [
|
||||
DocumentFactory::makeFromPath('document.docx', '/path/to/file'),
|
||||
DocumentFactory::makeFromPath('document2.docx', '/path/to/file'),
|
||||
];
|
||||
$request = new OfficeRequest($files);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$files</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'document.docx'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">),</span>
|
||||
<span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'document2.docx'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">),</span>
|
||||
<span class="p">];</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OfficeRequest</span><span class="p">(</span><span class="nv">$files</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.orientation" href="#office.orientation">
|
||||
@@ -1221,18 +1240,18 @@ $client->store($request, $dest);
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\OfficeRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\OfficeRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$files = [
|
||||
DocumentFactory::makeFromPath('document.docx', '/path/to/file'),
|
||||
];
|
||||
$request = new OfficeRequest($files);
|
||||
$request->setLandscape(true);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$files</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'document.docx'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">),</span>
|
||||
<span class="p">];</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OfficeRequest</span><span class="p">(</span><span class="nv">$files</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setLandscape</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.page_ranges" href="#office.page_ranges">
|
||||
@@ -1279,18 +1298,18 @@ applied for each document.</p>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\OfficeRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\OfficeRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$files = [
|
||||
DocumentFactory::makeFromPath('document.docx', '/path/to/file'),
|
||||
];
|
||||
$request = new OfficeRequest($files);
|
||||
$request->setPageRanges('1-3');
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$files</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'document.docx'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">),</span>
|
||||
<span class="p">];</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OfficeRequest</span><span class="p">(</span><span class="nv">$files</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setPageRanges</span><span class="p">(</span><span class="s1">'1-3'</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
@@ -1344,18 +1363,18 @@ will merge them and return the resulting PDF file.</p>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\MergeRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\MergeRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$files = [
|
||||
DocumentFactory::makeFromPath('file.pdf', '/path/to/file'),
|
||||
DocumentFactory::makeFromPath('file2.pdf', '/path/to/file'),
|
||||
];
|
||||
$request = new MergeRequest($files);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$files</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'file.pdf'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">),</span>
|
||||
<span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'file2.pdf'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">),</span>
|
||||
<span class="p">];</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MergeRequest</span><span class="p">(</span><span class="nv">$files</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
@@ -1407,17 +1426,17 @@ If unsucessful, it returns a <code>504</code> HTTP code.</p>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
use TheCodingMachine\Gotenberg\Request;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Request</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$request = new HTMLRequest($index);
|
||||
$request->setWaitTimeout(2.5);
|
||||
$dest = 'result.pdf';
|
||||
$client->store($request, $dest);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setWaitTimeout</span><span class="p">(</span><span class="mf">2.5</span><span class="p">);</span>
|
||||
<span class="nv">$dest</span> <span class="o">=</span> <span class="s1">'result.pdf'</span><span class="p">;</span>
|
||||
<span class="nv">$client</span><span class="o">-></span><span class="na">store</span><span class="p">(</span><span class="nv">$request</span><span class="p">,</span> <span class="nv">$dest</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
@@ -1465,15 +1484,15 @@ to given URL.</p>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$request = new HTMLRequest($index);
|
||||
$request->setWebhookURL('http://myapp.com/webhook/');
|
||||
$resp = $client->post($request);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setWebhookURL</span><span class="p">(</span><span class="s1">'http://myapp.com/webhook/'</span><span class="p">);</span>
|
||||
<span class="nv">$resp</span> <span class="o">=</span> <span class="nv">$client</span><span class="o">-></span><span class="na">post</span><span class="p">(</span><span class="nv">$request</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="webhook.timeout" href="#webhook.timeout">
|
||||
@@ -1520,16 +1539,16 @@ $resp = $client->post($request);
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$request = new HTMLRequest($index);
|
||||
$request->setWebhookURL('http://myapp.com/webhook/');
|
||||
$request->setWebhookURLTimeout(2.5);
|
||||
$resp = $client->post($request);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setWebhookURL</span><span class="p">(</span><span class="s1">'http://myapp.com/webhook/'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setWebhookURLTimeout</span><span class="p">(</span><span class="mf">2.5</span><span class="p">);</span>
|
||||
<span class="nv">$resp</span> <span class="o">=</span> <span class="nv">$client</span><span class="o">-></span><span class="na">post</span><span class="p">(</span><span class="nv">$request</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="webhook.custom_http_headers" href="#webhook.custom_http_headers">
|
||||
@@ -1579,16 +1598,16 @@ canonical key for <code>accept-encoding</code> is <code>Accept-Encoding</code>.<
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$request = new HTMLRequest($index);
|
||||
$request->setWebhookURL('http://myapp.com/webhook/');
|
||||
$request->addWebhookURLHTTPHeader('Your-Header', 'Foo');
|
||||
$resp = $client->post($request);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setWebhookURL</span><span class="p">(</span><span class="s1">'http://myapp.com/webhook/'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">addWebhookURLHTTPHeader</span><span class="p">(</span><span class="s1">'Your-Header'</span><span class="p">,</span> <span class="s1">'Foo'</span><span class="p">);</span>
|
||||
<span class="nv">$resp</span> <span class="o">=</span> <span class="nv">$client</span><span class="o">-></span><span class="na">post</span><span class="p">(</span><span class="nv">$request</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
@@ -1638,16 +1657,16 @@ Otherwise a random filename is used.</p>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||
</a>PHP</h3>
|
||||
|
||||
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
|
||||
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||
use TheCodingMachine\Gotenberg\HTMLRequest;
|
||||
use TheCodingMachine\Gotenberg\Request;
|
||||
<pre class="chroma"><span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Client</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\DocumentFactory</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\HTMLRequest</span><span class="p">;</span>
|
||||
<span class="k">use</span> <span class="nx">TheCodingMachine\Gotenberg\Request</span><span class="p">;</span>
|
||||
|
||||
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
|
||||
$index = DocumentFactory::makeFromPath('index.html', '/path/to/file');
|
||||
$request = new HTMLRequest($index);
|
||||
$request->setResultFilename('foo.pdf');
|
||||
$resp = $client->post($request);
|
||||
<span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Client</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">,</span> <span class="k">new</span> <span class="nx">\Http\Adapter\Guzzle6\Client</span><span class="p">());</span>
|
||||
<span class="nv">$index</span> <span class="o">=</span> <span class="nx">DocumentFactory</span><span class="o">::</span><span class="na">makeFromPath</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="s1">'/path/to/file'</span><span class="p">);</span>
|
||||
<span class="nv">$request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HTMLRequest</span><span class="p">(</span><span class="nv">$index</span><span class="p">);</span>
|
||||
<span class="nv">$request</span><span class="o">-></span><span class="na">setResultFilename</span><span class="p">(</span><span class="s1">'foo.pdf'</span><span class="p">);</span>
|
||||
<span class="nv">$resp</span> <span class="o">=</span> <span class="nv">$client</span><span class="o">-></span><span class="na">post</span><span class="p">(</span><span class="nv">$request</span><span class="p">);</span>
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
@@ -1696,14 +1715,14 @@ if the API is under heavy load.</p>
|
||||
|
||||
<p>For instance, using the following Docker Compose file:</p>
|
||||
|
||||
<pre class="chroma"><span class="k">version</span><span class="p">:</span><span class="w"> </span><span class="s1">'3'</span><span class="w">
|
||||
<pre class="chroma"><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s1">'3'</span><span class="w">
|
||||
</span><span class="w">
|
||||
</span><span class="w"></span><span class="k">services</span><span class="p">:</span><span class="w">
|
||||
</span><span class="w"></span><span class="nt">services</span><span class="p">:</span><span class="w">
|
||||
</span><span class="w">
|
||||
</span><span class="w"> </span><span class="c"># your others services</span><span class="w">
|
||||
</span><span class="w"> </span><span class="c"># your other services</span><span class="w">
|
||||
</span><span class="w">
|
||||
</span><span class="w"> </span><span class="k">gotenberg</span><span class="p">:</span><span class="w">
|
||||
</span><span class="w"> </span><span class="k">image</span><span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">6</span><span class="w">
|
||||
</span><span class="w"> </span><span class="nt">gotenberg</span><span class="p">:</span><span class="w">
|
||||
</span><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">thecodingmachine/gotenberg:6</span><span class="w">
|
||||
</span></pre>
|
||||
|
||||
<p>You may now launch your services using:</p>
|
||||
@@ -1761,7 +1780,8 @@ restart your Gotenberg instances from time to time to ensure a nominal behaviour
|
||||
<ul>
|
||||
<li>Follow the progress on the <a href="https://github.com/thecodingmachine/gotenberg">GitHub repository</a></li>
|
||||
<li>Follow <a href="https://twitter.com/gulnap">@gulnap</a> on Twitter</li>
|
||||
<li>Thanks to <a href="https://github.com/mafredri">@mafredri</a> for its help and its wonderful <a href="https://github.com/mafredri/cdp">cdp</a> library</li>
|
||||
<li>Thanks to <a href="https://github.com/mafredri">@mafredri</a> for his help and his wonderful <a href="https://github.com/mafredri/cdp">cdp</a> library</li>
|
||||
<li>OpenAPI documentation for the API can be found <a href="https://github.com/thecodingmachine/gotenberg/blob/master/docs/openapi.yaml">on GitHub</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
558
docs/openapi.yaml
Normal file
558
docs/openapi.yaml
Normal file
@@ -0,0 +1,558 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Gotenberg
|
||||
version: 6.3.1
|
||||
license:
|
||||
name: MIT
|
||||
url: 'https://github.com/thecodingmachine/gotenberg/blob/master/LICENSE'
|
||||
contact:
|
||||
url: 'https://github.com/thecodingmachine/gotenberg'
|
||||
description: >-
|
||||
A Docker-powered stateless API for converting HTML, Markdown and Office
|
||||
documents to PDF.
|
||||
servers:
|
||||
- url: 'http://localhost:3000'
|
||||
description: Local server with the default Docker image and port
|
||||
paths:
|
||||
/convert/html:
|
||||
post:
|
||||
summary: Convert a given HTML file to PDF
|
||||
description: >-
|
||||
Send an HTML file called `index.html` as a multipart form request, and
|
||||
get the resulting PDF file. You can optionally include `header.html` and
|
||||
`footer.html` files as part of the request as well.
|
||||
|
||||
|
||||
An example `index.html` file can be as follows:
|
||||
|
||||
```html
|
||||
|
||||
<!doctype html>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>My PDF</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello world!</h1>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
|
||||
You may also add a header and/or a footer in the resulting PDF by
|
||||
sending a file named `header.html` and `footer.html` respectively. Both
|
||||
the header and the footer files has to be a complete HTML document. An
|
||||
example `footer.html` can be as follows:
|
||||
|
||||
```html
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-size: 8rem;
|
||||
margin: 4rem auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
<span class="pageNumber"></span> of <span class="totalPages"></span>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
|
||||
The following classes will allow you to inject printing values in your
|
||||
document:
|
||||
|
||||
- `date`: Formatted print date.
|
||||
|
||||
- `title`: Document title.
|
||||
|
||||
- `pageNumber`: Current page number.
|
||||
|
||||
- `totalPage`: Total pages in the document.
|
||||
|
||||
|
||||
There are some limitations with header and footer files:
|
||||
|
||||
- JavaScript is not executed.
|
||||
|
||||
- External resources are not loaded.
|
||||
|
||||
- The CSS properties are independant of the ones used in the
|
||||
`index.html` file.
|
||||
|
||||
- `footer.html` CSS properties override the ones from `header.html`.
|
||||
|
||||
- Only fonts installed in the Docker image are loaded (see the fonts
|
||||
section)
|
||||
|
||||
- Images only work using a `base64` encoded source, e.g. `<img
|
||||
src="data:image/png;base64, iVBORw0K... />`
|
||||
|
||||
- `background-color` and `color` CSS properties require an additional
|
||||
`-webkit-print-color-adjust: exact` CSS property in order to work.
|
||||
requestBody:
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HTMLConvertRequestBody'
|
||||
description: >-
|
||||
The request body must have an `index.html` file in the `files` array,
|
||||
as well as all the referred resources on the same level as the
|
||||
`index.html` file. The request can also include `header.html` and
|
||||
`footer.html`, given the limitations in the API description above.
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/SuccessfulPDF'
|
||||
/convert/url:
|
||||
post:
|
||||
summary: Convert the contents of a given URL to PDF
|
||||
description: >-
|
||||
Send a remote URL in your API request via the `remoteURL` parameter, and
|
||||
get the resulting PDF file. The API will fetch the given URL and render
|
||||
the page to PDF using the underlying headless Chrome instance.
|
||||
requestBody:
|
||||
required: true
|
||||
description: >-
|
||||
The URL conversion request has to be a `multipart/form-data` request
|
||||
that includes a `remoteURL`. The API uses a headless Chrome instance
|
||||
to do the conversion, therefore print parameter such as margins and
|
||||
paper size are also accepted as optional parameters.
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
$ref: '#/components/schemas/URLConvertRequestBody'
|
||||
examples: {}
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/SuccessfulPDF'
|
||||
/convert/markdown:
|
||||
post:
|
||||
summary: Convert a Markdown file to PDF
|
||||
description: >-
|
||||
Send an HTML file called `index.html` as a multipart form request and
|
||||
embed a markdown file into the HTML file using the Golang template
|
||||
function `toHTML`, the API will convert the markdown and embed it into
|
||||
the HTML this way and render the resulting page. Markdown conversion
|
||||
works almost exactly the same way as HTML conversion, therefore refer to
|
||||
the HTML conversion page for all the options you can use when converting
|
||||
Markdown documents as well. You can optionally include `header.html` and
|
||||
`footer.html` files as part of the request as well.
|
||||
|
||||
|
||||
An example `index.html` file can be as follows:
|
||||
|
||||
```html
|
||||
|
||||
<!doctype html>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>My PDF</title>
|
||||
</head>
|
||||
<body>
|
||||
{{ toHTML .DirPath "file.md" }}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
|
||||
Whereas your `file.md` file in the same level would be like:
|
||||
|
||||
```md
|
||||
|
||||
# Title
|
||||
|
||||
Content
|
||||
|
||||
```
|
||||
|
||||
|
||||
The API will convert the markdown to HTML and embed it into your
|
||||
`index.html` file, then render the resulting page. You can include your
|
||||
own styling and more in your HTML file.
|
||||
requestBody:
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MarkdownConvertRequestBody'
|
||||
description: >-
|
||||
The request body must have an `index.html` file in the `files` array,
|
||||
as well as all the referred markdown resources on the same level as
|
||||
the `index.html` file.
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/SuccessfulPDF'
|
||||
/convert/office:
|
||||
post:
|
||||
summary: Convert an Office document to PDF
|
||||
description: >-
|
||||
Send one or more Office documents and get the resulting PDF file by
|
||||
merging all the files. The following file extensions are accepted:
|
||||
|
||||
- `.txt`
|
||||
|
||||
- `.rtf`
|
||||
|
||||
- `.fodt`
|
||||
|
||||
- `.doc`
|
||||
|
||||
- `.docx`
|
||||
|
||||
- `.odt`
|
||||
|
||||
- `.xls`
|
||||
|
||||
- `.xlsx`
|
||||
|
||||
- `.ods`
|
||||
|
||||
- `.ppt`
|
||||
|
||||
- `.pptx`
|
||||
|
||||
- `.odp`
|
||||
|
||||
|
||||
All files will be merged into a single PDF.
|
||||
|
||||
> **Attention:** The files will be merged alphabetically for the
|
||||
resulting PDF.
|
||||
|
||||
|
||||
You may also specify the page ranges to convert from the incoming Office
|
||||
documents. The expected format is the same as the one from the print
|
||||
options of LibreOffice, e.g. `1-1` or `1-4`.
|
||||
|
||||
|
||||
> **Attention:** if more than one document, the page ranges will be
|
||||
applied for each document.
|
||||
requestBody:
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
$ref: '#/components/schemas/OfficeConvertRequestBody'
|
||||
description: >-
|
||||
The request body must have an `index.html` file in the `files` array,
|
||||
as well as all the referred markdown resources on the same level as
|
||||
the `index.html` file.
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/SuccessfulPDF'
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties: {}
|
||||
/convert/merge:
|
||||
post:
|
||||
summary: Merge multiple PDFs into a single PDF
|
||||
description: >-
|
||||
You can send multiple PDF files to this endpoint, the API will merge
|
||||
them into a single PDF and return the resulting PDF file.
|
||||
|
||||
|
||||
> **Attention:** The PDF files will be merged alphabetically.
|
||||
requestBody:
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
files:
|
||||
type: array
|
||||
description: >-
|
||||
List of HTML files to be converted to PDF. An `index.html`
|
||||
file is required, and any other resources that are
|
||||
referenced through the HTML file must be included as well.
|
||||
All the referenced files must be on the same level as the
|
||||
`index.html` file.
|
||||
items:
|
||||
type: string
|
||||
format: binary
|
||||
resultFilename:
|
||||
type: string
|
||||
example: output.pdf
|
||||
description: >-
|
||||
If provided, the API will return the resulting PDF file with
|
||||
the given filename. Otherwise a random filename is used.
|
||||
required:
|
||||
- files
|
||||
description: >-
|
||||
The request body must have an `index.html` file in the `files` array,
|
||||
as well as all the referred markdown resources on the same level as
|
||||
the `index.html` file.
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/SuccessfulPDF'
|
||||
/ping:
|
||||
get:
|
||||
summary: Your GET endpoint
|
||||
tags: []
|
||||
responses:
|
||||
'200':
|
||||
description: The API is working fine.
|
||||
operationId: ''
|
||||
description: >-
|
||||
A simple endpoint to use as a healthcheck for the API availability with
|
||||
a simple request.
|
||||
components:
|
||||
schemas:
|
||||
HTMLConvertRequestBody:
|
||||
title: HTML Conversion Request Body
|
||||
type: object
|
||||
properties:
|
||||
files:
|
||||
type: array
|
||||
description: >-
|
||||
List of HTML files to be converted to PDF. An `index.html` file is
|
||||
required, and any other resources that are referenced through the
|
||||
HTML file must be included as well. All the referenced files must be
|
||||
on the same level as the `index.html` file.
|
||||
items:
|
||||
type: string
|
||||
format: binary
|
||||
marginTop:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Top margin for the page in inches.
|
||||
marginBottom:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Bottom margin for the page in inches.
|
||||
marginLeft:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Left margin for the page in inches.
|
||||
marginRight:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Right margin for the page in inches.
|
||||
paperWidth:
|
||||
type: number
|
||||
example: 8.27
|
||||
description: >-
|
||||
Paper width to be used while rendering the PDF. The default page
|
||||
size is A4.
|
||||
paperHeight:
|
||||
type: number
|
||||
example: 11.69
|
||||
description: >-
|
||||
Paper height to be used while rendering the PDF. The default page
|
||||
size is A4.
|
||||
landscape:
|
||||
type: boolean
|
||||
example: true
|
||||
default: false
|
||||
description: >-
|
||||
The default orientation for rendering the page is "portrait" mode.
|
||||
By sending "landscape" parameter, you can ask the output to be
|
||||
landscape.
|
||||
resultFilename:
|
||||
type: string
|
||||
example: output.pdf
|
||||
description: >-
|
||||
If provided, the API will return the resulting PDF file with the
|
||||
given filename. Otherwise a random filename is used.
|
||||
required:
|
||||
- files
|
||||
MarkdownConvertRequestBody:
|
||||
title: Markdown Conversion Request Body
|
||||
type: object
|
||||
properties:
|
||||
files:
|
||||
type: array
|
||||
description: >-
|
||||
List of HTML files to be converted to PDF. An `index.html` file is
|
||||
required, and any other resources that are referenced through the
|
||||
HTML file must be included as well. All the referenced files must be
|
||||
on the same level as the `index.html` file.
|
||||
items:
|
||||
type: string
|
||||
format: binary
|
||||
marginTop:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Top margin for the page in inches.
|
||||
marginBottom:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Bottom margin for the page in inches.
|
||||
marginLeft:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Left margin for the page in inches.
|
||||
marginRight:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Right margin for the page in inches.
|
||||
paperWidth:
|
||||
type: number
|
||||
example: 8.27
|
||||
description: >-
|
||||
Paper width to be used while rendering the PDF. The default page
|
||||
size is A4.
|
||||
paperHeight:
|
||||
type: number
|
||||
example: 11.69
|
||||
description: >-
|
||||
Paper height to be used while rendering the PDF. The default page
|
||||
size is A4.
|
||||
landscape:
|
||||
type: boolean
|
||||
example: true
|
||||
default: false
|
||||
description: >-
|
||||
The default orientation for rendering the page is "portrait" mode.
|
||||
By sending "landscape" parameter, you can ask the output to be
|
||||
landscape.
|
||||
resultFilename:
|
||||
type: string
|
||||
example: output.pdf
|
||||
description: >-
|
||||
If provided, the API will return the resulting PDF file with the
|
||||
given filename. Otherwise a random filename is used.
|
||||
required:
|
||||
- files
|
||||
URLConvertRequestBody:
|
||||
title: URL Conversion Request Body
|
||||
type: object
|
||||
properties:
|
||||
remoteURL:
|
||||
type: string
|
||||
example: 'https://google.com'
|
||||
marginTop:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Top margin for the page in inches.
|
||||
marginBottom:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Bottom margin for the page in inches.
|
||||
marginLeft:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Left margin for the page in inches.
|
||||
marginRight:
|
||||
type: number
|
||||
example: 0
|
||||
default: 1
|
||||
description: Right margin for the page in inches.
|
||||
paperWidth:
|
||||
type: number
|
||||
example: 8.27
|
||||
description: >-
|
||||
Paper width to be used while rendering the PDF. The default page
|
||||
size is A4.
|
||||
paperHeight:
|
||||
type: number
|
||||
example: 11.69
|
||||
description: >-
|
||||
Paper height to be used while rendering the PDF. The default page
|
||||
size is A4.
|
||||
landscape:
|
||||
type: boolean
|
||||
example: true
|
||||
default: false
|
||||
description: >-
|
||||
The default orientation for rendering the page is "portrait" mode.
|
||||
By sending "landscape" parameter, you can ask the output to be
|
||||
landscape.
|
||||
resultFilename:
|
||||
type: string
|
||||
example: output.pdf
|
||||
description: >-
|
||||
If provided, the API will return the resulting PDF file with the
|
||||
given filename. Otherwise a random filename is used.
|
||||
required:
|
||||
- remoteURL
|
||||
OfficeConvertRequestBody:
|
||||
title: Office Conversion Request Body
|
||||
type: object
|
||||
properties:
|
||||
files:
|
||||
type: array
|
||||
description: >-
|
||||
List of HTML files to be converted to PDF. An `index.html` file is
|
||||
required, and any other resources that are referenced through the
|
||||
HTML file must be included as well. All the referenced files must be
|
||||
on the same level as the `index.html` file.
|
||||
items:
|
||||
type: string
|
||||
format: binary
|
||||
pageRanges:
|
||||
type: string
|
||||
example: 1-3
|
||||
description: >-
|
||||
The page ranges to be converted to PDF for the incoming Office
|
||||
documents. **If there are multiple files sent to the API, this page
|
||||
range will apply to all of the documents**.
|
||||
landscape:
|
||||
type: boolean
|
||||
example: true
|
||||
default: false
|
||||
description: >-
|
||||
The default orientation for rendering the page is "portrait" mode.
|
||||
By sending "landscape" parameter, you can ask the output to be
|
||||
landscape.
|
||||
resultFilename:
|
||||
type: string
|
||||
example: output.pdf
|
||||
description: >-
|
||||
If provided, the API will return the resulting PDF file with the
|
||||
given filename. Otherwise a random filename is used.
|
||||
required:
|
||||
- files
|
||||
MergeFilesRequestBody:
|
||||
title: Merge Files Request Body
|
||||
type: object
|
||||
properties:
|
||||
files:
|
||||
type: array
|
||||
description: >-
|
||||
List of HTML files to be converted to PDF. An `index.html` file is
|
||||
required, and any other resources that are referenced through the
|
||||
HTML file must be included as well. All the referenced files must be
|
||||
on the same level as the `index.html` file.
|
||||
items:
|
||||
type: string
|
||||
format: binary
|
||||
resultFilename:
|
||||
type: string
|
||||
example: output.pdf
|
||||
description: >-
|
||||
If provided, the API will return the resulting PDF file with the
|
||||
given filename. Otherwise a random filename is used.
|
||||
required:
|
||||
- files
|
||||
securitySchemes: {}
|
||||
responses:
|
||||
SuccessfulPDF:
|
||||
description: Resulting PDF file from the conversion.
|
||||
content:
|
||||
application/pdf:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
32
go.mod
32
go.mod
@@ -1,30 +1,26 @@
|
||||
module github.com/thecodingmachine/gotenberg
|
||||
|
||||
go 1.13
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/google/go-cmp v0.3.1 // indirect
|
||||
github.com/gorilla/websocket v1.4.1 // indirect
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/labstack/echo/v4 v4.1.11
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/labstack/echo/v4 v4.1.16
|
||||
github.com/labstack/gommon v0.3.0
|
||||
github.com/mafredri/cdp v0.25.0
|
||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.11
|
||||
github.com/mafredri/cdp v0.28.0
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/microcosm-cc/bluemonday v1.0.2
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
|
||||
github.com/russross/blackfriday/v2 v2.0.1
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/valyala/fasttemplate v1.1.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 // indirect
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
||||
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 // indirect
|
||||
github.com/sirupsen/logrus v1.6.0
|
||||
github.com/stretchr/testify v1.6.1
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 // indirect
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect
|
||||
golang.org/x/text v0.3.2
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.7 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c // indirect
|
||||
)
|
||||
|
||||
100
go.sum
100
go.sum
@@ -1,41 +1,39 @@
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/labstack/echo/v4 v4.1.11 h1:z0BZoArY4FqdpUEl+wlHp4hnr/oSR6MTmQmv8OHSoww=
|
||||
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labstack/echo/v4 v4.1.16 h1:8swiwjE5Jkai3RPfZoahp8kjVCRNq+y7Q0hPji2Kz0o=
|
||||
github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI=
|
||||
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/mafredri/cdp v0.25.0 h1:nXhdpjP8Nrhw+9jnMlljEF6xs2B3vXI/wSiKDOvOXGs=
|
||||
github.com/mafredri/cdp v0.25.0/go.mod h1:hgdiA0yp1uqhSaDOHJWPgXpMbh+LAfUdD9vbN2AM8gE=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mafredri/cdp v0.28.0 h1:v/LWC3GpactA1EaS737bl+eNUhvOaDh+FzvyoDxNM5o=
|
||||
github.com/mafredri/cdp v0.28.0/go.mod h1:11586MgpyJuQR4qiXQ/7HBame2FtGIBzymaUHZcQ0PY=
|
||||
github.com/mafredri/go-lint v0.0.0-20180911205320-920981dfc79e/go.mod h1:k/zdyxI3q6dup24o8xpYjJKTCf2F7rfxLp6w/efTiWs=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
@@ -44,47 +42,61 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4=
|
||||
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 h1:gSbV7h1NRL2G1xTg/owz62CST1oJBmxy4QpMMregXVQ=
|
||||
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200330183114-f8bfb4ee3038 h1:FUufmZ17Dp41BwLDPii6R8vp0QtIquTiDIxcbFlY1ek=
|
||||
golang.org/x/tools v0.0.0-20200330183114-f8bfb4ee3038/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/thecodingmachine/gotenberg/internal/app/xhttp/pkg/context"
|
||||
"github.com/thecodingmachine/gotenberg/internal/app/xhttp/pkg/resource"
|
||||
"github.com/thecodingmachine/gotenberg/internal/pkg/chrome"
|
||||
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
|
||||
"github.com/thecodingmachine/gotenberg/internal/pkg/printer"
|
||||
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
|
||||
@@ -69,7 +70,17 @@ func pingHandler(c echo.Context) error {
|
||||
const op string = "xhttp.pingHandler"
|
||||
ctx := context.MustCastFromEchoContext(c)
|
||||
logger := ctx.XLogger()
|
||||
config := ctx.Config()
|
||||
|
||||
logger.DebugOp(op, "handling ping request...")
|
||||
|
||||
if !config.DisableGoogleChrome() {
|
||||
_, err := chrome.IsViable(logger)
|
||||
if err != nil {
|
||||
return xerror.New(op, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -239,13 +250,13 @@ func convert(ctx context.Context, p printer.Printer) error {
|
||||
// and directly return the resulting PDF file
|
||||
// or an error.
|
||||
if !r.HasArg(resource.WebhookURLArgKey) {
|
||||
logger.DebugfOp(op, "no '%s' found, converting synchronously", resource.WebhookURLArgKey)
|
||||
logger.DebugOpf(op, "no '%s' found, converting synchronously", resource.WebhookURLArgKey)
|
||||
return convertSync(ctx, p, filename, fpath)
|
||||
}
|
||||
// as a webhook URL has been given, we
|
||||
// run the following lines in a goroutine so that
|
||||
// it doesn't block.
|
||||
logger.DebugfOp(op, "'%s' found, converting asynchronously", resource.WebhookURLArgKey)
|
||||
logger.DebugOpf(op, "'%s' found, converting asynchronously", resource.WebhookURLArgKey)
|
||||
return convertAsync(ctx, p, filename, fpath)
|
||||
}
|
||||
if err := resolver(); err != nil {
|
||||
@@ -264,7 +275,7 @@ func convertSync(ctx context.Context, p printer.Printer, filename, fpath string)
|
||||
return err
|
||||
}
|
||||
if !r.HasArg(resource.ResultFilenameArgKey) {
|
||||
logger.DebugfOp(
|
||||
logger.DebugOpf(
|
||||
op,
|
||||
"no '%s' found, using generated filename '%s'",
|
||||
resource.RemoteURLArgKey,
|
||||
@@ -275,7 +286,7 @@ func convertSync(ctx context.Context, p printer.Printer, filename, fpath string)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
logger.DebugfOp(
|
||||
logger.DebugOpf(
|
||||
op,
|
||||
"'%s' found, so not using generated filename",
|
||||
resource.ResultFilenameArgKey,
|
||||
@@ -308,7 +319,7 @@ func convertAsync(ctx context.Context, p printer.Printer, filename, fpath string
|
||||
return xerror.New(op, err)
|
||||
}
|
||||
go func() {
|
||||
defer r.Close() // nolint: errcheck
|
||||
defer r.Close()
|
||||
if err := p.Print(fpath); err != nil {
|
||||
xerr := xerror.New(op, err)
|
||||
logger.ErrorOp(xerror.Op(xerr), xerr)
|
||||
@@ -320,8 +331,8 @@ func convertAsync(ctx context.Context, p printer.Printer, filename, fpath string
|
||||
logger.ErrorOp(xerror.Op(xerr), xerr)
|
||||
return
|
||||
}
|
||||
defer f.Close() // nolint: errcheck
|
||||
logger.DebugfOp(
|
||||
defer f.Close()
|
||||
logger.DebugOpf(
|
||||
op,
|
||||
"preparing to send result file '%s' to '%s'...",
|
||||
filename,
|
||||
@@ -342,13 +353,13 @@ func convertAsync(ctx context.Context, p printer.Printer, filename, fpath string
|
||||
if len(customHTTPHeaders) > 0 {
|
||||
for key, value := range customHTTPHeaders {
|
||||
req.Header.Set(key, value)
|
||||
logger.DebugfOp(op, "set '%s' to custom HTTP header '%s'", value, key)
|
||||
logger.DebugOpf(op, "set '%s' to custom HTTP header '%s'", value, key)
|
||||
}
|
||||
} else {
|
||||
logger.DebugOp(op, "skipping custom HTTP headers as none have been provided...")
|
||||
}
|
||||
// send the result file.
|
||||
logger.DebugfOp(
|
||||
logger.DebugOpf(
|
||||
op,
|
||||
"sending result file '%s' to '%s'...",
|
||||
filename,
|
||||
@@ -360,8 +371,8 @@ func convertAsync(ctx context.Context, p printer.Printer, filename, fpath string
|
||||
logger.ErrorOp(xerror.Op(xerr), xerr)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close() // nolint: errcheck
|
||||
logger.DebugfOp(
|
||||
defer resp.Body.Close()
|
||||
logger.DebugOpf(
|
||||
op,
|
||||
"result file '%s' sent to '%s'",
|
||||
filename,
|
||||
|
||||
@@ -56,6 +56,10 @@ func chromePrinterOptions(r resource.Resource, config conf.Config) (printer.Chro
|
||||
if err != nil {
|
||||
return printer.ChromePrinterOptions{}, err
|
||||
}
|
||||
scale, err := resource.ScaleArg(r, config)
|
||||
if err != nil {
|
||||
return printer.ChromePrinterOptions{}, err
|
||||
}
|
||||
return printer.ChromePrinterOptions{
|
||||
WaitTimeout: waitTimeout,
|
||||
WaitDelay: waitDelay,
|
||||
@@ -71,6 +75,7 @@ func chromePrinterOptions(r resource.Resource, config conf.Config) (printer.Chro
|
||||
PageRanges: pageRanges,
|
||||
RpccBufferSize: googleChromeRpccBufferSize,
|
||||
CustomHTTPHeaders: make(map[string]string),
|
||||
Scale: scale,
|
||||
}, nil
|
||||
}
|
||||
opts, err := resolver()
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -105,8 +106,10 @@ func (ctx *Context) WithResource(directoryName string) error {
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
defer in.Close() // nolint: errcheck
|
||||
if err := r.WithFile(fh.Filename, in); err != nil {
|
||||
defer in.Close()
|
||||
// avoid directory traversal.
|
||||
filename := filepath.Base(fh.Filename)
|
||||
if err := r.WithFile(filename, in); err != nil {
|
||||
return r, err
|
||||
}
|
||||
}
|
||||
@@ -167,14 +170,14 @@ func (ctx Context) LogRequestResult(err error, isDebug bool) error {
|
||||
"bytes_out": bytesOut(resp),
|
||||
}
|
||||
if err != nil {
|
||||
ctx.logger.WithFields(fields).ErrorfOp(op, "request failed")
|
||||
ctx.logger.WithFields(fields).ErrorOpf(op, "request failed")
|
||||
return err
|
||||
}
|
||||
if isDebug {
|
||||
ctx.logger.WithFields(fields).DebugfOp(op, "request handled")
|
||||
ctx.logger.WithFields(fields).DebugOpf(op, "request handled")
|
||||
return nil
|
||||
}
|
||||
ctx.logger.WithFields(fields).InfofOp(op, "request handled")
|
||||
ctx.logger.WithFields(fields).InfoOpf(op, "request handled")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@ const (
|
||||
// GoogleChromeRpccBufferSizeArgKey is the key
|
||||
// of the argument "googleChromeRpccBufferSize".
|
||||
GoogleChromeRpccBufferSizeArgKey ArgKey = "googleChromeRpccBufferSize"
|
||||
// ScaleArgKey is the key
|
||||
// of the argument "scale".
|
||||
ScaleArgKey ArgKey = "scale"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -81,6 +84,7 @@ func ArgKeys() []ArgKey {
|
||||
LandscapeArgKey,
|
||||
PageRangesArgKey,
|
||||
GoogleChromeRpccBufferSizeArgKey,
|
||||
ScaleArgKey,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,3 +298,22 @@ func GoogleChromeRpccBufferSizeArg(r Resource, config conf.Config) (int64, error
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
/*
|
||||
ScaleArg is a helper for retrieving
|
||||
the "scale" argument as float64.
|
||||
*/
|
||||
func ScaleArg(r Resource, config conf.Config) (float64, error) {
|
||||
const op string = "resource.ScaleArg"
|
||||
opts := printer.DefaultChromePrinterOptions(config)
|
||||
result, err := r.Float64Arg(
|
||||
ScaleArgKey,
|
||||
opts.Scale,
|
||||
xassert.Float64NotInferiorTo(0.1),
|
||||
xassert.Float64NotSuperiorTo(2.0),
|
||||
)
|
||||
if err != nil {
|
||||
return result, xerror.New(op, err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ func TestArgKeys(t *testing.T) {
|
||||
LandscapeArgKey,
|
||||
PageRangesArgKey,
|
||||
GoogleChromeRpccBufferSizeArgKey,
|
||||
ScaleArgKey,
|
||||
}
|
||||
assert.Equal(t, expected, ArgKeys())
|
||||
}
|
||||
@@ -346,3 +347,50 @@ func TestGoogleChromeRpccBufferSizeArg(t *testing.T) {
|
||||
err = r.Close()
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestScaleArg(t *testing.T) {
|
||||
const (
|
||||
resourceDirectoryName string = "foo"
|
||||
defaultValue float64 = 1.0
|
||||
)
|
||||
var expected float64
|
||||
logger := test.DebugLogger()
|
||||
config := conf.DefaultConfig()
|
||||
r, err := New(logger, resourceDirectoryName)
|
||||
assert.Nil(t, err)
|
||||
// argument does not exist.
|
||||
expected = defaultValue
|
||||
v, err := ScaleArg(r, config)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, v)
|
||||
// argument exist.
|
||||
expected = 0.5
|
||||
r.WithArg(ScaleArgKey, "0.5")
|
||||
v, err = ScaleArg(r, config)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, v)
|
||||
// should not be OK as argument
|
||||
// value is < 0.1.
|
||||
expected = defaultValue
|
||||
r.WithArg(ScaleArgKey, "-1.0")
|
||||
v, err = ScaleArg(r, config)
|
||||
test.AssertError(t, err)
|
||||
assert.Equal(t, expected, v)
|
||||
// should not be OK as argument
|
||||
// value is > 2.0.
|
||||
expected = defaultValue
|
||||
r.WithArg(ScaleArgKey, "2.1")
|
||||
v, err = ScaleArg(r, config)
|
||||
test.AssertError(t, err)
|
||||
assert.Equal(t, expected, v)
|
||||
// should not be OK as
|
||||
// argument value is invalid.
|
||||
expected = defaultValue
|
||||
r.WithArg(ScaleArgKey, "foo")
|
||||
v, err = ScaleArg(r, config)
|
||||
test.AssertError(t, err)
|
||||
assert.Equal(t, expected, v)
|
||||
// finally...
|
||||
err = r.Close()
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ func (f file) write(in io.Reader) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close() // nolint: errcheck
|
||||
if err := out.Chmod(0644); err != nil {
|
||||
defer out.Close()
|
||||
if err := out.Chmod(0600); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(out, in); err != nil {
|
||||
|
||||
@@ -50,7 +50,7 @@ func New(logger xlog.Logger, directoryName string) (Resource, error) {
|
||||
if err != nil {
|
||||
return Resource{}, xerror.New(op, err)
|
||||
}
|
||||
logger.DebugfOp(op, "resource directory '%s' created", directoryName)
|
||||
logger.DebugOpf(op, "resource directory '%s' created", directoryName)
|
||||
return Resource{
|
||||
logger: logger,
|
||||
dirPath: dirPath,
|
||||
@@ -65,13 +65,13 @@ func New(logger xlog.Logger, directoryName string) (Resource, error) {
|
||||
func (r Resource) Close() error {
|
||||
const op string = "resource.Resource.Close"
|
||||
if _, err := os.Stat(r.dirPath); os.IsNotExist(err) {
|
||||
r.logger.DebugfOp(op, "resource directory '%s' does not exist, nothing to remove", r.dirPath)
|
||||
r.logger.DebugOpf(op, "resource directory '%s' does not exist, nothing to remove", r.dirPath)
|
||||
return nil
|
||||
}
|
||||
if err := os.RemoveAll(r.dirPath); err != nil {
|
||||
return xerror.New(op, err)
|
||||
}
|
||||
r.logger.DebugfOp(op, "resource directory '%s' removed", r.dirPath)
|
||||
r.logger.DebugOpf(op, "resource directory '%s' removed", r.dirPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -84,17 +84,17 @@ func (r *Resource) WithCustomHTTPHeader(key string, value string) {
|
||||
if strings.Contains(canonicalKey, RemoteURLCustomHTTPHeaderCanonicalBaseKey) ||
|
||||
strings.Contains(canonicalKey, WebhookURLCustomHTTPHeaderCanonicalBaseKey) {
|
||||
r.customHeaders[canonicalKey] = value
|
||||
r.logger.DebugfOp(op, "added '%s' with value '%s' to resource custom HTTP headers", canonicalKey, value)
|
||||
r.logger.DebugOpf(op, "added '%s' with value '%s' to resource custom HTTP headers", canonicalKey, value)
|
||||
return
|
||||
}
|
||||
r.logger.DebugfOp(op, "skipping '%s' as it is not a custom HTTP header...", canonicalKey)
|
||||
r.logger.DebugOpf(op, "skipping '%s' as it is not a custom HTTP header...", canonicalKey)
|
||||
}
|
||||
|
||||
// WithArg add a new argument to the Resource.
|
||||
func (r *Resource) WithArg(key ArgKey, value string) {
|
||||
const op string = "resource.Resource.WithArg"
|
||||
r.args[key] = value
|
||||
r.logger.DebugfOp(op, "added '%s' with value '%s' to resource args", key, value)
|
||||
r.logger.DebugOpf(op, "added '%s' with value '%s' to resource args", key, value)
|
||||
}
|
||||
|
||||
// WithFile add a new file to the Resource.
|
||||
@@ -112,7 +112,7 @@ func (r *Resource) WithFile(filename string, in io.Reader) error {
|
||||
return err
|
||||
}
|
||||
r.files[filename] = file
|
||||
r.logger.DebugfOp(op, "resource file '%s' created", filename)
|
||||
r.logger.DebugOpf(op, "resource file '%s' created", filename)
|
||||
return nil
|
||||
}
|
||||
if err := resolver(); err != nil {
|
||||
|
||||
@@ -16,11 +16,11 @@ import (
|
||||
)
|
||||
|
||||
// Start starts Google Chrome headless in background.
|
||||
func Start(logger xlog.Logger) error {
|
||||
func Start(logger xlog.Logger, ignoreCertificateErrors bool) error {
|
||||
const op string = "chrome.Start"
|
||||
logger.DebugOp(op, "starting new Google Chrome headless process on port 9222...")
|
||||
resolver := func() error {
|
||||
cmd, err := cmd(logger)
|
||||
cmd, err := cmd(logger, ignoreCertificateErrors)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -31,8 +31,9 @@ func Start(logger xlog.Logger) error {
|
||||
}
|
||||
// if the process failed to start correctly,
|
||||
// we have to restart it.
|
||||
if !isViable(logger) {
|
||||
return restart(logger, cmd.Process)
|
||||
isViable, _ := IsViable(logger)
|
||||
if !isViable {
|
||||
return restart(logger, cmd.Process, ignoreCertificateErrors)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -42,7 +43,7 @@ func Start(logger xlog.Logger) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func cmd(logger xlog.Logger) (*exec.Cmd, error) {
|
||||
func cmd(logger xlog.Logger, ignoreCertificateErrors bool) (*exec.Cmd, error) {
|
||||
const op string = "chrome.cmd"
|
||||
binary := "google-chrome-stable"
|
||||
args := []string{
|
||||
@@ -50,8 +51,9 @@ func cmd(logger xlog.Logger) (*exec.Cmd, error) {
|
||||
"--headless",
|
||||
// see https://github.com/thecodingmachine/gotenberg/issues/157.
|
||||
"--disable-dev-shm-usage",
|
||||
// see https://github.com/GoogleChrome/puppeteer/issues/2410.
|
||||
"--font-render-hinting=medium",
|
||||
// See https://github.com/puppeteer/puppeteer/issues/661
|
||||
// and https://github.com/puppeteer/puppeteer/issues/2410.
|
||||
"--font-render-hinting=none",
|
||||
"--remote-debugging-port=9222",
|
||||
"--disable-gpu",
|
||||
"--disable-translate",
|
||||
@@ -65,6 +67,11 @@ func cmd(logger xlog.Logger) (*exec.Cmd, error) {
|
||||
"--mute-audio",
|
||||
"--no-first-run",
|
||||
}
|
||||
|
||||
if ignoreCertificateErrors {
|
||||
args = append(args, "--ignore-certificate-errors")
|
||||
}
|
||||
|
||||
cmd, err := xexec.Command(logger, binary, args...)
|
||||
if err != nil {
|
||||
return nil, xerror.New(op, err)
|
||||
@@ -92,7 +99,7 @@ func kill(logger xlog.Logger, proc *os.Process) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func restart(logger xlog.Logger, proc *os.Process) error {
|
||||
func restart(logger xlog.Logger, proc *os.Process, ignoreCertificateErrors bool) error {
|
||||
const op string = "chrome.restart"
|
||||
logger.DebugOp(op, "restarting Google Chrome headless process using port 9222...")
|
||||
resolver := func() error {
|
||||
@@ -100,7 +107,7 @@ func restart(logger xlog.Logger, proc *os.Process) error {
|
||||
if err := kill(logger, proc); err != nil {
|
||||
return err
|
||||
}
|
||||
cmd, err := cmd(logger)
|
||||
cmd, err := cmd(logger, ignoreCertificateErrors)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -111,8 +118,9 @@ func restart(logger xlog.Logger, proc *os.Process) error {
|
||||
}
|
||||
// if the process failed to restart correctly,
|
||||
// we have to restart it again.
|
||||
if !isViable(logger) {
|
||||
return restart(logger, cmd.Process)
|
||||
isViable, _ := IsViable(logger)
|
||||
if !isViable {
|
||||
return restart(logger, cmd.Process, ignoreCertificateErrors)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -122,48 +130,54 @@ func restart(logger xlog.Logger, proc *os.Process) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func isViable(logger xlog.Logger) bool {
|
||||
// IsViable checks if Google Chrome is healthy.
|
||||
func IsViable(logger xlog.Logger) (bool, error) {
|
||||
const (
|
||||
op string = "chrome.isViable"
|
||||
op string = "chrome.IsViable"
|
||||
maxViabilityTests int = 20
|
||||
)
|
||||
viable := func() bool {
|
||||
viable := func() (bool, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
endpoint := "http://localhost:9222"
|
||||
logger.DebugfOp(
|
||||
logger.DebugOpf(
|
||||
op,
|
||||
"checking Google Chrome headless process viability via endpoint '%s/json/version'",
|
||||
endpoint,
|
||||
)
|
||||
v, err := devtool.New(endpoint).Version(ctx)
|
||||
if err != nil {
|
||||
logger.DebugfOp(
|
||||
logger.DebugOpf(
|
||||
op,
|
||||
"Google Chrome headless is not viable as endpoint returned '%v'",
|
||||
err.Error(),
|
||||
)
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
logger.DebugfOp(
|
||||
logger.DebugOpf(
|
||||
op,
|
||||
"Google Chrome headless is viable as endpoint returned '%v'",
|
||||
v,
|
||||
)
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
result := false
|
||||
var err error
|
||||
|
||||
for i := 0; i < maxViabilityTests && !result; i++ {
|
||||
warmup(logger)
|
||||
result = viable()
|
||||
result, err = viable()
|
||||
}
|
||||
return result
|
||||
return result, err
|
||||
}
|
||||
|
||||
func warmup(logger xlog.Logger) {
|
||||
const op string = "chrome.warmup"
|
||||
warmupTime := xtime.Duration(0.5)
|
||||
logger.DebugfOp(
|
||||
const (
|
||||
op string = "chrome.warmup"
|
||||
seconds float64 = 0.5
|
||||
)
|
||||
warmupTime := xtime.Duration(seconds)
|
||||
logger.DebugOpf(
|
||||
op,
|
||||
"waiting '%v' for allowing Google Chrome to warmup",
|
||||
warmupTime,
|
||||
|
||||
@@ -40,41 +40,46 @@ const (
|
||||
// DefaultGoogleChromeRpccBufferSizeEnvVar contains the name
|
||||
// of the environment variable "DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE".
|
||||
DefaultGoogleChromeRpccBufferSizeEnvVar string = "DEFAULT_GOOGLE_CHROME_RPCC_BUFFER_SIZE"
|
||||
// GoogleChromeIgnoreCertificateErrorsEnvVar contains the name
|
||||
// of the environment variable "GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS".
|
||||
GoogleChromeIgnoreCertificateErrorsEnvVar string = "GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS"
|
||||
)
|
||||
|
||||
// Config contains the application
|
||||
// configuration.
|
||||
type Config struct {
|
||||
maximumWaitTimeout float64
|
||||
maximumWaitDelay float64
|
||||
maximumWebhookURLTimeout float64
|
||||
defaultWaitTimeout float64
|
||||
defaultWebhookURLTimeout float64
|
||||
defaultListenPort int64
|
||||
disableGoogleChrome bool
|
||||
disableUnoconv bool
|
||||
logLevel xlog.Level
|
||||
rootPath string
|
||||
maximumGoogleChromeRpccBufferSize int64
|
||||
defaultGoogleChromeRpccBufferSize int64
|
||||
maximumWaitTimeout float64
|
||||
maximumWaitDelay float64
|
||||
maximumWebhookURLTimeout float64
|
||||
defaultWaitTimeout float64
|
||||
defaultWebhookURLTimeout float64
|
||||
defaultListenPort int64
|
||||
disableGoogleChrome bool
|
||||
disableUnoconv bool
|
||||
googleChromeIgnoreCertificateErrors bool
|
||||
logLevel xlog.Level
|
||||
rootPath string
|
||||
maximumGoogleChromeRpccBufferSize int64
|
||||
defaultGoogleChromeRpccBufferSize int64
|
||||
}
|
||||
|
||||
// DefaultConfig returns the default
|
||||
// configuration.
|
||||
func DefaultConfig() Config {
|
||||
return Config{
|
||||
maximumWaitTimeout: 30.0,
|
||||
maximumWaitDelay: 10.0,
|
||||
maximumWebhookURLTimeout: 30.0,
|
||||
defaultWaitTimeout: 10.0,
|
||||
defaultWebhookURLTimeout: 10.0,
|
||||
defaultListenPort: 3000,
|
||||
disableGoogleChrome: false,
|
||||
disableUnoconv: false,
|
||||
logLevel: xlog.InfoLevel,
|
||||
rootPath: "/",
|
||||
maximumGoogleChromeRpccBufferSize: 104857600, // ~100 MB
|
||||
defaultGoogleChromeRpccBufferSize: 1048576, // 1 MB
|
||||
maximumWaitTimeout: 30.0,
|
||||
maximumWaitDelay: 10.0,
|
||||
maximumWebhookURLTimeout: 30.0,
|
||||
defaultWaitTimeout: 10.0,
|
||||
defaultWebhookURLTimeout: 10.0,
|
||||
defaultListenPort: 3000,
|
||||
disableGoogleChrome: false,
|
||||
disableUnoconv: false,
|
||||
logLevel: xlog.InfoLevel,
|
||||
rootPath: "/",
|
||||
maximumGoogleChromeRpccBufferSize: 104857600, // ~100 MB
|
||||
defaultGoogleChromeRpccBufferSize: 1048576, // 1 MB
|
||||
googleChromeIgnoreCertificateErrors: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,6 +193,14 @@ func FromEnv() (Config, error) {
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
googleChromeIgnoreCertificateErrors, err := xassert.BoolFromEnv(
|
||||
GoogleChromeIgnoreCertificateErrorsEnvVar,
|
||||
c.googleChromeIgnoreCertificateErrors,
|
||||
)
|
||||
c.googleChromeIgnoreCertificateErrors = googleChromeIgnoreCertificateErrors
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
result, err := resolver()
|
||||
@@ -274,3 +287,7 @@ func (c Config) MaximumGoogleChromeRpccBufferSize() int64 {
|
||||
func (c Config) DefaultGoogleChromeRpccBufferSize() int64 {
|
||||
return c.defaultGoogleChromeRpccBufferSize
|
||||
}
|
||||
|
||||
func (c Config) GoogleChromeIgnoreCertificateErrors() bool {
|
||||
return c.googleChromeIgnoreCertificateErrors
|
||||
}
|
||||
|
||||
@@ -380,6 +380,43 @@ func TestDefaultGoogleChromeRpccBufferSizeFromEnv(t *testing.T) {
|
||||
os.Unsetenv(DefaultGoogleChromeRpccBufferSizeEnvVar)
|
||||
}
|
||||
|
||||
func TestGoogleChromeIgnoreCertificateErrorsFromEnv(t *testing.T) {
|
||||
var (
|
||||
expected Config
|
||||
result Config
|
||||
err error
|
||||
)
|
||||
// GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS correctly set to true.
|
||||
os.Setenv(GoogleChromeIgnoreCertificateErrorsEnvVar, "1")
|
||||
expected = DefaultConfig()
|
||||
expected.googleChromeIgnoreCertificateErrors = true
|
||||
result, err = FromEnv()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
os.Unsetenv(GoogleChromeIgnoreCertificateErrorsEnvVar)
|
||||
// GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS correctly set to false.
|
||||
os.Setenv(GoogleChromeIgnoreCertificateErrorsEnvVar, "0")
|
||||
expected = DefaultConfig()
|
||||
expected.googleChromeIgnoreCertificateErrors = false
|
||||
result, err = FromEnv()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
os.Unsetenv(GoogleChromeIgnoreCertificateErrorsEnvVar)
|
||||
// GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS wrongly set.
|
||||
os.Setenv(GoogleChromeIgnoreCertificateErrorsEnvVar, "foo")
|
||||
expected = DefaultConfig()
|
||||
result, err = FromEnv()
|
||||
test.AssertError(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
os.Unsetenv(GoogleChromeIgnoreCertificateErrorsEnvVar)
|
||||
// GOOGLE_CHROME_IGNORE_CERTIFICATE_ERRORS not set at all.
|
||||
expected = DefaultConfig()
|
||||
expected.googleChromeIgnoreCertificateErrors = false
|
||||
result, err = FromEnv()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
}
|
||||
|
||||
func TestGetters(t *testing.T) {
|
||||
result := DefaultConfig()
|
||||
assert.Equal(t, result.maximumWaitTimeout, result.MaximumWaitTimeout())
|
||||
@@ -394,4 +431,5 @@ func TestGetters(t *testing.T) {
|
||||
assert.Equal(t, result.rootPath, result.RootPath())
|
||||
assert.Equal(t, result.maximumGoogleChromeRpccBufferSize, result.MaximumGoogleChromeRpccBufferSize())
|
||||
assert.Equal(t, result.defaultGoogleChromeRpccBufferSize, result.DefaultGoogleChromeRpccBufferSize())
|
||||
assert.Equal(t, result.googleChromeIgnoreCertificateErrors, result.GoogleChromeIgnoreCertificateErrors())
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ type ChromePrinterOptions struct {
|
||||
PageRanges string
|
||||
RpccBufferSize int64
|
||||
CustomHTTPHeaders map[string]string
|
||||
Scale float64
|
||||
}
|
||||
|
||||
// DefaultChromePrinterOptions returns the default
|
||||
@@ -66,6 +67,7 @@ func DefaultChromePrinterOptions(config conf.Config) ChromePrinterOptions {
|
||||
PageRanges: "",
|
||||
RpccBufferSize: config.DefaultGoogleChromeRpccBufferSize(),
|
||||
CustomHTTPHeaders: make(map[string]string),
|
||||
Scale: 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,10 +94,11 @@ func (p chromePrinter) Print(destination string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer devtConn.Close() // nolint: errcheck
|
||||
defer devtConn.Close()
|
||||
// create a new CDP Client that uses conn.
|
||||
devtClient := cdp.NewClient(devtConn)
|
||||
newContextTarget, err := devtClient.Target.CreateBrowserContext(ctx)
|
||||
createBrowserContextArgs := target.NewCreateBrowserContextArgs()
|
||||
newContextTarget, err := devtClient.Target.CreateBrowserContext(ctx, createBrowserContextArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -133,7 +136,7 @@ func (p chromePrinter) Print(destination string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer newContextConn.Close() // nolint: errcheck
|
||||
defer newContextConn.Close()
|
||||
// create a new CDP Client that uses newContextConn.
|
||||
targetClient := cdp.NewClient(newContextConn)
|
||||
/*
|
||||
@@ -160,7 +163,7 @@ func (p chromePrinter) Print(destination string) error {
|
||||
// apply a wait delay (if any).
|
||||
if p.opts.WaitDelay > 0.0 {
|
||||
// wait for a given amount of time (useful for javascript delay).
|
||||
p.logger.DebugfOp(op, "applying a wait delay of '%.2fs'...", p.opts.WaitDelay)
|
||||
p.logger.DebugOpf(op, "applying a wait delay of '%.2fs'...", p.opts.WaitDelay)
|
||||
time.Sleep(xtime.Duration(p.opts.WaitDelay))
|
||||
} else {
|
||||
p.logger.DebugOp(op, "no wait delay to apply, moving on...")
|
||||
@@ -176,12 +179,13 @@ func (p chromePrinter) Print(destination string) error {
|
||||
SetDisplayHeaderFooter(true).
|
||||
SetHeaderTemplate(p.opts.HeaderHTML).
|
||||
SetFooterTemplate(p.opts.FooterHTML).
|
||||
SetPrintBackground(true)
|
||||
SetPrintBackground(true).
|
||||
SetScale(p.opts.Scale)
|
||||
if p.opts.PageRanges != "" {
|
||||
printToPdfArgs.SetPageRanges(p.opts.PageRanges)
|
||||
}
|
||||
// print the page to PDF.
|
||||
print, err := targetClient.Page.PrintToPDF(
|
||||
// printToPDF the page to PDF.
|
||||
printToPDF, err := targetClient.Page.PrintToPDF(
|
||||
ctx,
|
||||
printToPdfArgs,
|
||||
)
|
||||
@@ -206,7 +210,7 @@ func (p chromePrinter) Print(destination string) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(destination, print.Data, 0644); err != nil {
|
||||
if err := ioutil.WriteFile(destination, printToPDF.Data, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -279,7 +283,7 @@ func (p chromePrinter) setCustomHTTPHeaders(ctx context.Context, client *cdp.Cli
|
||||
// useless but for the logs.
|
||||
for key, value := range p.opts.CustomHTTPHeaders {
|
||||
customHTTPHeaders[key] = value
|
||||
p.logger.DebugfOp(op, "set '%s' to custom HTTP header '%s'", value, key)
|
||||
p.logger.DebugOpf(op, "set '%s' to custom HTTP header '%s'", value, key)
|
||||
}
|
||||
b, err := json.Marshal(customHTTPHeaders)
|
||||
if err != nil {
|
||||
@@ -310,22 +314,22 @@ func (p chromePrinter) listenEvents(ctx context.Context, client *cdp.Client) err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer domContentEventFired.Close() // nolint: errcheck
|
||||
defer domContentEventFired.Close()
|
||||
loadEventFired, err := client.Page.LoadEventFired(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer loadEventFired.Close() // nolint: errcheck
|
||||
defer loadEventFired.Close()
|
||||
lifecycleEvent, err := client.Page.LifecycleEvent(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lifecycleEvent.Close() // nolint: errcheck
|
||||
defer lifecycleEvent.Close()
|
||||
loadingFinished, err := client.Network.LoadingFinished(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer loadingFinished.Close() // nolint: errcheck
|
||||
defer loadingFinished.Close()
|
||||
if _, err := client.Page.Navigate(ctx, page.NewNavigateArgs(p.url)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -354,7 +358,7 @@ func (p chromePrinter) listenEvents(ctx context.Context, client *cdp.Client) err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.logger.DebugfOp(op, "event '%s' received", ev.Name)
|
||||
p.logger.DebugOpf(op, "event '%s' received", ev.Name)
|
||||
if ev.Name == networkIdleEventName {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -3,15 +3,14 @@ package printer
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
"github.com/russross/blackfriday/v2"
|
||||
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
|
||||
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
|
||||
"github.com/thecodingmachine/gotenberg/internal/pkg/xrand"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// NewMarkdownPrinter returns a Printer which
|
||||
@@ -36,7 +35,7 @@ func NewMarkdownPrinter(logger xlog.Logger, fpath string, opts ChromePrinterOpti
|
||||
baseFilename := xrand.Get()
|
||||
dst := fmt.Sprintf("%s/%s.html", dirPath, baseFilename)
|
||||
logger.DebugOp(op, "writing the HTML from previous conversion(s) into new file...")
|
||||
if err := ioutil.WriteFile(dst, buffer.Bytes(), 0644); err != nil {
|
||||
if err := ioutil.WriteFile(dst, buffer.Bytes(), 0600); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("file://%s", dst), nil
|
||||
@@ -58,6 +57,8 @@ type templateData struct {
|
||||
|
||||
func markdownToHTML(dirPath, filename string) (template.HTML, error) {
|
||||
const op string = "printer.markdownToHTML"
|
||||
// avoid directory traversal.
|
||||
filename = filepath.Base(filename)
|
||||
fpath := fmt.Sprintf("%s/%s", dirPath, filename)
|
||||
b, err := ioutil.ReadFile(fpath)
|
||||
if err != nil {
|
||||
|
||||
@@ -57,7 +57,7 @@ func (p mergePrinter) Print(destination string) error {
|
||||
}
|
||||
// see https://github.com/thecodingmachine/gotenberg/issues/139.
|
||||
sort.Strings(p.fpaths)
|
||||
p.logger.DebugfOp(op, "merging '%v'...", p.fpaths)
|
||||
p.logger.DebugOpf(op, "merging '%v'...", p.fpaths)
|
||||
resolver := func() error {
|
||||
var args []string
|
||||
args = append(args, p.fpaths...)
|
||||
|
||||
@@ -64,11 +64,11 @@ func (p officePrinter) Print(destination string) error {
|
||||
for i, fpath := range p.fpaths {
|
||||
baseFilename := xrand.Get()
|
||||
tmpDest := fmt.Sprintf("%s/%d%s.pdf", dirPath, i, baseFilename)
|
||||
p.logger.DebugfOp(op, "converting '%s' to PDF...", fpath)
|
||||
p.logger.DebugOpf(op, "converting '%s' to PDF...", fpath)
|
||||
if err := p.unoconv(ctx, fpath, tmpDest); err != nil {
|
||||
return err
|
||||
}
|
||||
p.logger.DebugfOp(op, "'%s.pdf' created", baseFilename)
|
||||
p.logger.DebugOpf(op, "'%s.pdf' created", baseFilename)
|
||||
fpaths[i] = tmpDest
|
||||
}
|
||||
if len(fpaths) == 1 {
|
||||
@@ -94,13 +94,14 @@ func (p officePrinter) Print(destination string) error {
|
||||
func (p officePrinter) unoconv(ctx context.Context, fpath, destination string) error {
|
||||
const op string = "printer.unoconv"
|
||||
resolver := func() error {
|
||||
dirName := xrand.Get()
|
||||
port, err := freeport.GetFreePort()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
args := []string{
|
||||
"--user-profile",
|
||||
fmt.Sprintf("///tmp/%d", port),
|
||||
fmt.Sprintf("///tmp/%s", dirName),
|
||||
"--port",
|
||||
fmt.Sprintf("%d", port),
|
||||
"--format",
|
||||
@@ -113,7 +114,11 @@ func (p officePrinter) unoconv(ctx context.Context, fpath, destination string) e
|
||||
args = append(args, "--export", fmt.Sprintf("PageRange=%s", p.opts.PageRanges))
|
||||
}
|
||||
args = append(args, "--output", destination, fpath)
|
||||
if err := xexec.Run(ctx, p.logger, "unoconv", args...); err != nil {
|
||||
err = xexec.Run(ctx, p.logger, "unoconv", args...)
|
||||
// always remove user profile folders created by LibreOffice.
|
||||
// see https://github.com/thecodingmachine/gotenberg/issues/192.
|
||||
go cleanupUserProfile(p.logger, dirName)
|
||||
if err != nil {
|
||||
// find a way to check it in the handlers?
|
||||
if p.opts.PageRanges != "" && strings.Contains(err.Error(), "exit status 5") {
|
||||
return xerror.Invalid(
|
||||
@@ -132,6 +137,15 @@ func (p officePrinter) unoconv(ctx context.Context, fpath, destination string) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func cleanupUserProfile(logger xlog.Logger, dirName string) {
|
||||
const op = "printer.cleanupUserProfile"
|
||||
path := fmt.Sprintf("/tmp/%s", dirName)
|
||||
if err := os.RemoveAll(path); err != nil {
|
||||
// find a way to bubble up this error?
|
||||
logger.ErrorOpf(op, "failed to remove user profile directory '%s': %s", path, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Compile-time checks to ensure type implements desired interfaces.
|
||||
var (
|
||||
_ = Printer(new(officePrinter))
|
||||
|
||||
@@ -12,5 +12,5 @@ type Printer interface {
|
||||
|
||||
func logOptions(logger xlog.Logger, opts interface{}) {
|
||||
const op string = "printer.logOptions"
|
||||
logger.DebugfOp(op, "options: %+v", opts)
|
||||
logger.DebugOpf(op, "options: %+v", opts)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
// times out after given seconds.
|
||||
func WithTimeout(logger xlog.Logger, seconds float64) (context.Context, context.CancelFunc) {
|
||||
const op string = "xcontext.WithTimeout"
|
||||
logger.DebugfOp(op, "creating context with '%.2fs' of timeout...", seconds)
|
||||
logger.DebugOpf(op, "creating context with '%.2fs' of timeout...", seconds)
|
||||
return context.WithTimeout(context.Background(), xtime.Duration(seconds))
|
||||
}
|
||||
|
||||
|
||||
@@ -84,11 +84,11 @@ func Run(ctx context.Context, logger xlog.Logger, binary string, args ...string)
|
||||
}()
|
||||
select {
|
||||
case err := <-result:
|
||||
logger.DebugfOp(op, "command '%s' finished", strings.Join(cmd.Args, " "))
|
||||
logger.DebugOpf(op, "command '%s' finished", strings.Join(cmd.Args, " "))
|
||||
kill()
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
logger.DebugfOp(op, "command '%s' failed to finish before context.Context deadline", strings.Join(cmd.Args, " "))
|
||||
logger.DebugOpf(op, "command '%s' failed to finish before context.Context deadline", strings.Join(cmd.Args, " "))
|
||||
kill()
|
||||
return ctx.Err()
|
||||
}
|
||||
@@ -102,7 +102,7 @@ func Run(ctx context.Context, logger xlog.Logger, binary string, args ...string)
|
||||
// LogBeforeExecute logs a command before its execution.
|
||||
func LogBeforeExecute(logger xlog.Logger, cmd *exec.Cmd) {
|
||||
const op string = "xexec.LogBeforeExecute"
|
||||
logger.DebugfOp(op, "executing command: %s", strings.Join(cmd.Args, " "))
|
||||
logger.DebugOpf(op, "executing command: %s", strings.Join(cmd.Args, " "))
|
||||
}
|
||||
|
||||
func pipe(logger xlog.Logger, cmd *exec.Cmd) error {
|
||||
@@ -139,7 +139,7 @@ func logCommandOutput(logger xlog.Logger, reader io.ReadCloser, outputType strin
|
||||
}
|
||||
op := buf.String()
|
||||
r := bufio.NewReader(reader)
|
||||
defer reader.Close() // nolint: errcheck
|
||||
defer reader.Close()
|
||||
for {
|
||||
line, _, err := r.ReadLine()
|
||||
if err != nil {
|
||||
|
||||
@@ -104,9 +104,9 @@ func (l Logger) DebugOp(op, message string) {
|
||||
l.entry.WithField("op", op).Debug(message)
|
||||
}
|
||||
|
||||
// DebugfOp logs a debug message for given
|
||||
// DebugOpf logs a debug message for given
|
||||
// logical operation and format.
|
||||
func (l Logger) DebugfOp(op, format string, args ...interface{}) {
|
||||
func (l Logger) DebugOpf(op, format string, args ...interface{}) {
|
||||
l.entry.WithField("op", op).Debugf(format, args...)
|
||||
}
|
||||
|
||||
@@ -116,9 +116,9 @@ func (l Logger) InfoOp(op, message string) {
|
||||
l.entry.WithField("op", op).Info(message)
|
||||
}
|
||||
|
||||
// InfofOp logs an info message for given
|
||||
// InfoOpf logs an info message for given
|
||||
// logical operation and format.
|
||||
func (l Logger) InfofOp(op, format string, args ...interface{}) {
|
||||
func (l Logger) InfoOpf(op, format string, args ...interface{}) {
|
||||
l.entry.WithField("op", op).Infof(format, args...)
|
||||
}
|
||||
|
||||
@@ -128,9 +128,9 @@ func (l Logger) ErrorOp(op string, err error) {
|
||||
l.entry.WithField("op", op).Error(err.Error())
|
||||
}
|
||||
|
||||
// ErrorfOp logs an error message for given
|
||||
// ErrorOpf logs an error message for given
|
||||
// logical operation and format.
|
||||
func (l Logger) ErrorfOp(op, format string, args ...interface{}) {
|
||||
func (l Logger) ErrorOpf(op, format string, args ...interface{}) {
|
||||
l.entry.WithField("op", op).Errorf(format, args...)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ if [ $VERSION_LENGTH -ne 3 ]; then
|
||||
fi
|
||||
|
||||
docker build \
|
||||
--build-arg VERSION=${VERSION} \
|
||||
--build-arg VERSION=${VERSION} \
|
||||
--build-arg TINI_VERSION=${TINI_VERSION} \
|
||||
-t ${DOCKER_REGISTRY}/gotenberg:latest \
|
||||
-t ${DOCKER_REGISTRY}/gotenberg:${SEMVER[0]} \
|
||||
|
||||
@@ -14,7 +14,7 @@ func main() {
|
||||
systemLogger.FatalOp(op, err)
|
||||
}
|
||||
// start Google Chrome headless.
|
||||
if err := chrome.Start(systemLogger); err != nil {
|
||||
if err := chrome.Start(systemLogger, config.GoogleChromeIgnoreCertificateErrors()); err != nil {
|
||||
systemLogger.FatalOp(op, err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user