composition

package
v2.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2019 License: MIT Imports: 20 Imported by: 0

README

lib-ui-service: composition

This library contains code for the composition of HTML pages out of multiple HTML pages, containing fragments.

Key Concept

Every service delivers a functional HTML user interface in form of complete HTML pages. This way a service is self contained and can be developed and tested by it's own. A UI-Service can request multiple pages from different services and compose them to one HTML page. To support this, the HTML pages from the services contain a special HTML vocabulary.

Composition Process

The composition is done in the following steps:

  1. A UI-Service has a CompositionHandler in it's handler chain, which answers these which need composition.
  2. The CompositionHandler has a callback from the UI-Service. This callback gets a http.Request object as argument and returns a List of FetchResult.
  3. For each request this callback is triggered. So the UI-Service can add a ContentFetcher for this request and adds FetchDefinitions for Page using ContentFetcher.AddFetchJob().
  4. The ContentFetcher loads the Pages and recursively their dependencies in parallel. For the actual loading and parsing, it uses the HtmlContentParser.
  5. When all Content objects are loaded, the CompositionHandler merges them together, using ContentMerge.
Merging

The merging itself is very simple:

  • The MetaJSON is calculated by adding all fields of the loaded MetaJSON to one global map.
  • All Head fragments are concatenated within the <head>.
  • For rendering of the body part, the default fragment of the page with the name layout is rendered first. This rendering may recursively include other fragments.
  • All Tail fragments are concatenated at the end of the <body>.
Execution Order

Attention: The execution order of the Content Objects is determined by the order in which they are returned from the ContentFetcher. Currently this is only deterministic within the FetchDefinitions added by ContentFetcher.AddFetchJob(). The recursive dependencies are loaded from them in a random order. This may cause nondeterministic behaviour, if they contain fragments with the same name or which provide the same MetaJSON attributes.

Caching

Caching is provided at the level of framents, if a cache from caching package is configured.

HTML Composition Vocabulary

Attribute uic-remove

A UI-Service has to remove the element marked with this attribute and all its subelements. Be careful to have a correct open and closing structure in the HTML. The standard selfclosing tags are allowed, e.g. both are working <br> and <br/>, but if there is a structure error with e.g. a div, uic-remove may lead to strange behaviour.

Example:

<link uic-remove rel="stylesheet" type="text/css" href="testing.css"/>

Where: Everywhere (head, body, within fragments)

Script type text/uic-meta

A HTML page may contain a script of type text/uic-meta, with a JSON object as content. The UI-Service has to add the contents of the JSON object to its global meta data object.

Example:

<script type="text/uic-meta">
  {
   "foo": "bar",
   "boo": "bazz",
   "categories": ["animal", "human"]
  }
</script>

Where: head

Fragments

The UI-Service interpretes an HTML page as a set of fragments. All those fragments are optional.

  • One Head Fragment, identified by the child elements of the HTML <head> tag.
  • One Body Default Fragement, identified by the child elements of the <body> tag or by a uic-fragment without a name attribute.
  • Multiple Named Body Fragments, identified by uic-fragment tag within the body.
  • One Tail Fragment, identified by the uic-tail tag.
Head-Fragment

The complete contents of the head is interpreted as the head fragment. The elements marked with uic-remove and the uic-meta script are not cleaned out of the head fragment. If the head framents only contains whitespace, it is interpreted as not existing.

Example: The Head Fragment contains <title>The Title</title>

<head>
  <title>The Title</title>
  <link uic-remove rel="stylesheet" type="text/css" href="special.css"/>
  <script type="text/uic-meta">
    {}
  </script>
</head>
Body Default Fragment

All other elements fragments and those elements, marked with uic-remove, are removed from the body and the remaining fragment is taken as Body Default Fragment. The Body Default Fragment is just a fragment with the empty name (""). If there is a uic-fragment tag without the name in the body, this overwrites the default fragment.

Example: The Default Fragment contains <h1>Hello World</h1>

<body>
    Hello World
    <ul uic-remove>
      <!-- A Navigation for testing -->
    </ul>
    <uic-fragment name="headline">
      <h1>This is a headline</h1>
    </uic-fragment>
</body>

The complete contents of the body is interpreted as the head fragment. The elements marked with uic-remove and the uic-meta script are not cleaned out of the head fragment. If the head fragments only contains whitespace, it is interpreted as not existing.

Example: The Default Fragment contains <h1>This is the default</h1>

<body>
    <h1>Hello World</h1>
    <uic-fragment>
      <h1>This is the default</h1>
    </uic-fragment>
</body>
Element uic-fragment

The body of an HTML page may contain multiple uic-fragment tags, which contain the fragments for the page. All content within the tag is taken as fragment content. Nested Fragment tags are not allowed.

The fragment tag may have a name attribute, for naming the fragment. If no attribute is given, or the name is empty, the Body Default Fragment is overwritten by this fragment.

Example: Contains two fragments headline and w

<body>
  <uic-fragment name="headline">
    <h1>This is a headline</h1>
  </uic-fragment>
  <uic-fragment name="w">
    Bli Bla blub
    <div uic-remove>
       Some element for testing
    </div>
  </uic-fragment>
</body>

Where: body

Templating

All fragments (except the Head Fragment) may contain minimal templating directives which have to be resolved by the UI-Service. There are two forms of includes and a syntax for variable replacement.

Variables

The UI-Service has to replace variables by the corresponding path out of the global meta data. If the variable name contains a '.', at first, it is attempted to match the full path as one string, after that, it is attempted to traverse a tree of maps.

Example:

§[ foo ]§

or

§[ foo.bar ]§ // tried to match MetaJSON['foo.bar'] and than MetaJSON['foo']['bar']
Predefined Variables

There are some predefined variables, constructed out of the request.

{'request': {
    'base_url': 'http://example.com/' // the base url of the service, calculated out of the request, e.g.
    'params: {..} // a map with the GET Query parameters of the request.
  }
}
Includes

On an unspecified include, the UI-Service has to replace the include by a previously loaded fragment. If the required fragment is missing, the composition will fail.

Example: Will be replaced by the Default Body Fragment of example.com/foo.

§[> example.com/foo]§

Example: Will be replaced by the content fragment of example.com/foo.

§[> example.com/foo#content]§

Example: Will be replaced by the content fragment of any random choosen page.

§[> #content]§
Optional Includes

There is a syntax for optional includes with an alternative text.

Example: Will be replaced by the contents of foo or by the alternative content, if no such element foo exists or an error occurs while replacing with foo.

§[#> foo]§ alternative content §[/foo]§
Include HTML Syntax

There is also an html syntax for includes, as following:

  <uic-include src="example.com/foo" required="true"/>

The default is required=false, if not specified. The alternative content for optional html includes is currently not implemented.

Includes with Paramters

The HTML Syntax allows to specify includes, which are not preloaded, but will be loaded from the ui service on demand. For the case, it is also possible to specify parameters on the include, which allow the ui service to influence the loading of the content containing the fragment.

Example:

<uic-include src="example.com/foo#content" param-foo="bar" param-bli="bla"/>

In this example, the ui service is requested to load the content associated with the fetch definition named 'example.com/foo' and the parameter map {foo: bar, bli: bla}. The content will only be loaded, if the there was not an content with the name example.com/foo before. Otherwise, the paramters will be ignored.

Attention: Parameter names are always converted to lower case names, because of the underlaying html parser,

Fetch directive

It is possible to specifiy a url for additional content to load, while the composition takes place.

Example:

  <uic-fetch src="example.com/foo" timeout="42000" required="false" name="foo"/>

The URL, referenced with the src Attribute will be fetched. It can than be referenced by the spcified name. E.g. like so:

  <uic-include src="foo#content"/>

Documentation

Index

Constants

View Source
const (
	LayoutFragmentName = "layout"
	FragmentSeparater  = "#"
	DefaultBufferSize  = 1024 * 100
)
View Source
const (
	DefaultTimeout  time.Duration = 10 * time.Second
	FileURLPrefix                 = "file://"
	DefaultPriority               = 0
)
View Source
const (
	UicRemove       = "uic-remove"
	UicInclude      = "uic-include"
	UicFetch        = "uic-fetch"
	UicFragment     = "uic-fragment"
	UicTail         = "uic-tail"
	ScriptTypeMeta  = "text/uic-meta"
	ParamAttrPrefix = "param-"
)
View Source
const (
	PlaceholderStart  = "§["
	PlaceholderEnd    = "]§"
	StartInclude      = ">"
	StartIncludeBlock = "#>"
	EndIncludeBlock   = "/"
)
View Source
const MAX_PRIORITY int = 4294967295

Variables

View Source
var ForwardRequestHeaders = []string{
	"Authorization",
	"Cache-Control",
	"Cookie",
	"Content-Length",
	"Content-Type",
	"If-Match",
	"If-Modified-Since",
	"If-None-Match",
	"If-Range",
	"If-Unmodified-Since",
	"Pragma",
	"Referer",
	"Transfer-Encoding",
	"X-Forwarded-Host",
	"X-Correlation-Id",
	"X-Feature-Toggle",
	"Host",
}

ForwardRequestHeaders are those headers, which are included from the original client request to the backend request. TODO: Add Host header to an XFF header

View Source
var ForwardResponseHeaders = []string{
	"Age",
	"Allow",
	"Cache-Control",
	"Content-Disposition",
	"Content-Security-Policy",
	"Content-Type",
	"Date",
	"ETag",
	"Expires",
	"Last-Modified",
	"Link",
	"Location",
	"Pragma",
	"Set-Cookie",
	"WWW-Authenticate"}

ForwardResponseHeaders are those headers, which are included from the servers backend response to the client.

View Source
var ResponseProcessorsNotApplicable = errors.New("request processors are not apliable on file content")

Functions

func LogFetchResultLoadingError

func LogFetchResultLoadingError(res *FetchResult, w http.ResponseWriter, r *http.Request)

func MetadataForRequest

func MetadataForRequest(r *http.Request) map[string]interface{}

func ParseHeadFragment

func ParseHeadFragment(fragment *StringFragment, headPropertyMap map[string]string) error

Types

type Cache

type Cache interface {
	Get(hash string) (cacheObject interface{}, found bool)
	Set(hash string, label string, memorySize int, cacheObject interface{})
	Invalidate()
	PurgeEntries(keys []string)
}

type CacheInvalidationHandler

type CacheInvalidationHandler struct {
	// contains filtered or unexported fields
}

func NewCacheInvalidationHandler

func NewCacheInvalidationHandler(cache Cache, next http.Handler) *CacheInvalidationHandler

func (*CacheInvalidationHandler) ServeHTTP

type CacheStrategy

type CacheStrategy interface {
	Hash(method string, url string, requestHeader http.Header) string
	IsCacheable(method string, url string, statusCode int, requestHeader http.Header, responseHeader http.Header) bool
}

type CachingContentLoader

type CachingContentLoader struct {
	// contains filtered or unexported fields
}

func NewCachingContentLoader

func NewCachingContentLoader(cache Cache) *CachingContentLoader

func (*CachingContentLoader) Load

func (loader *CachingContentLoader) Load(fd *FetchDefinition) (Content, error)

type CompositionHandler

type CompositionHandler struct {
	// contains filtered or unexported fields
}

func NewCompositionHandler

func NewCompositionHandler(contentFetcherFactory ContentFetcherFactory) *CompositionHandler

NewCompositionHandler creates a new Handler with the supplied defaultData, which is used for each request.

func NewCompositionHandlerWithCache

func NewCompositionHandlerWithCache(contentFetcherFactory ContentFetcherFactory, cache Cache) *CompositionHandler

NewCompositionHandlerWithCache creates a new Handler with the supplied defaultData, which is used for each request. Use this constructor, if you created a caching content loader and provide the handle to it's cache as argument.

func (*CompositionHandler) ServeHTTP

func (agg *CompositionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*CompositionHandler) WithCache

func (agg *CompositionHandler) WithCache(cache Cache) *CompositionHandler

func (*CompositionHandler) WithDeduplicationStrategyFactory

func (agg *CompositionHandler) WithDeduplicationStrategyFactory(strategyFactory func() StylesheetDeduplicationStrategy) *CompositionHandler

Set the deduplication strategy to be used by the constructed content merger This method will first take effect in the upcomping call of ServeHTTP()

type Content

type Content interface {

	// The Name of the content, as given in the fetch definition
	Name() string

	// RequiredContent returns a list of Content Elements to load
	RequiredContent() []*FetchDefinition

	// Dependencies returns list of referenced content element names.
	// The list only contains the base names of the includes e.g. 'foo' for '<uic-include src="foo#bar"/>'
	Dependencies() map[string]Params

	// Meta returns a data structure to add to the global
	// data context.
	Meta() map[string]interface{}

	// Head returns a partial which should be
	// inserted to the html head
	Head() Fragment

	// Body returns a map of partials,
	// the named body partials, where the keys are partial names.
	Body() map[string]Fragment

	// Tail returns a partial which should be inserted at the end of the page.
	// e.g. a script to load after rendering.
	Tail() Fragment

	// Deprecated: Return the attributes for the body element as Fragment.
	BodyAttributes() Fragment

	// Reader returns the stream with the content, of any.
	// If Reader() == nil, no stream is available an it contains parsed data, only.
	Reader() io.ReadCloser

	// HttpHeader() returns the http headers of the fetch job
	HttpHeader() http.Header

	// HttpStatusCode() returns the http statuc code of the fetch job
	HttpStatusCode() int

	// MemorySize return the estimated size in bytes, for this object in memory
	MemorySize() int
}

Content is the abstraction over includable data. Content may be parsed of it may contain a stream represented by a non nil Reader(), not both.

type ContentFetcher

type ContentFetcher struct {
	Loader ContentLoader
	// contains filtered or unexported fields
}

ContentFetcher is a type, which can fetch a set of Content pages in parallel.

func NewContentFetcher

func NewContentFetcher(defaultMetaJSON map[string]interface{}) *ContentFetcher

NewContentFetcher creates a ContentFetcher with an HtmlContentParser as default. TODO: The FetchResults should always be returned in a predictable order, independent of the actual response times of the fetch jobs.

func (*ContentFetcher) AddFetchJob

func (fetcher *ContentFetcher) AddFetchJob(d *FetchDefinition)

AddFetchJob adds one job to the fetcher and recursively adds the dependencies also.

func (*ContentFetcher) Empty

func (fetcher *ContentFetcher) Empty() bool

func (*ContentFetcher) MetaJSON

func (fetcher *ContentFetcher) MetaJSON() map[string]interface{}

func (*ContentFetcher) SetFetchDefinitionFactory

func (fetcher *ContentFetcher) SetFetchDefinitionFactory(factory FetchDefinitionFactory)

SetFetchDefinitionFactory supplies a factory for lazy evaluated fetch jobs, which will only be loaded if a fragment refrences them. Seting the factory of optional, but if used, has to be done before adding Jobs by AddFetchJob.

func (*ContentFetcher) WaitForResults

func (fetcher *ContentFetcher) WaitForResults() []*FetchResult

Wait blocks until all jobs are done, either successful or with an error result and returns the content and errors. Do we need to return the Results in a special order????

type ContentFetcherFactory

type ContentFetcherFactory func(r *http.Request) FetchResultSupplier

A ContentFetcherFactory returns a configured fetch job for a request which can return the fetch results.

type ContentLoader

type ContentLoader interface {
	// Load synchronously loads a content.
	// The loader has to ensure to return the call withing the supplied timeout.
	Load(fd *FetchDefinition) (content Content, err error)
}

type ContentMerge

type ContentMerge struct {
	MetaJSON       map[string]interface{}
	Head           []Fragment
	BodyAttrs      []Fragment
	BodyAttrsArray [][]html.Attribute

	// Aggregator for the Body Fragments of the results.
	// Each fragment is insertes twice with full name and local name,
	// The full name only ends with a FragmentSeparater ('#'), if the local name is not empty
	// and the local name is always prefixed with FragmentSeparater ('#').
	Body map[string]Fragment

	// Aggregator for the Tail Fragments of the results.
	Tail     []Fragment
	Buffered bool
	// contains filtered or unexported fields
}

ContentMerge is a helper type for creation of a combined html document out of multiple Content pages.

func NewContentMerge

func NewContentMerge(metaJSON map[string]interface{}) *ContentMerge

NewContentMerge creates a new buffered ContentMerge

func (*ContentMerge) AddContent

func (cntx *ContentMerge) AddContent(c Content, priority int)

func (*ContentMerge) GetBodyFragmentByName

func (cntx *ContentMerge) GetBodyFragmentByName(name string) (Fragment, bool)

GetBodyFragmentByName returns a fragment by ists name. If the name does not contain a FragmentSeparater ('#'), and no such fragment is found. also a lookup for '#name' is done, to check, if there is a local name matching. The bool return value indicates, if the fragment was found.

func (*ContentMerge) GetHtml

func (cntx *ContentMerge) GetHtml() ([]byte, error)

func (*ContentMerge) SetDeduplicationStrategy

func (cntx *ContentMerge) SetDeduplicationStrategy(strategy StylesheetDeduplicationStrategy)

type ContentMerger

type ContentMerger interface {
	// Add content to the merger
	AddContent(c Content, priority int)

	// Return the html as byte array
	GetHtml() ([]byte, error)

	// Set the stratgy for stylesheet deduplication
	SetDeduplicationStrategy(stategy StylesheetDeduplicationStrategy)
}

type ContentParser

type ContentParser interface {
	// Parse parses the input stream into a Content Object
	Parse(*MemoryContent, io.Reader) error
}

type ContentV2

type ContentV2 interface {
	Content

	// Return the attributes for the body element as array.
	BodyAttributesArray() []html.Attribute
}

type ContentWrapper

type ContentWrapper struct {
	Content
	// contains filtered or unexported fields
}

func (*ContentWrapper) Reader

func (cw *ContentWrapper) Reader() io.ReadCloser

type DefaultErrorHandler

type DefaultErrorHandler struct {
}

the default handler throws an status 502

func NewDefaultErrorHandler

func NewDefaultErrorHandler() *DefaultErrorHandler

func (*DefaultErrorHandler) Handle

func (der *DefaultErrorHandler) Handle(err error, status int, w http.ResponseWriter, r *http.Request)

type ErrorHandler

type ErrorHandler interface {
	// handle http request errors
	Handle(err error, status int, w http.ResponseWriter, r *http.Request)
}

type FetchDefinition

type FetchDefinition struct {
	// The name of the fetch definition
	Name                   string
	URL                    string
	Timeout                time.Duration
	FollowRedirects        bool
	Required               bool
	Header                 http.Header
	Method                 string
	Body                   io.Reader
	RespProc               ResponseProcessor
	ErrHandler             ErrorHandler
	CacheStrategy          CacheStrategy
	ServiceDiscoveryActive bool
	ServiceDiscovery       servicediscovery.ServiceDiscovery
	Priority               int
}

FetchDefinition is a descriptor for fetching Content from an endpoint.

func NewFetchDefinition

func NewFetchDefinition(url string) *FetchDefinition

Creates a fetch definition (warning: this one will not forward any request headers).

func (*FetchDefinition) DiscoveredBy

func (d *FetchDefinition) DiscoveredBy(dnsServer string) *FetchDefinition

Fluent-interface decorator for the FetchDefinition that activates the ServiceDiscovery

func (*FetchDefinition) FromRequest

func (fd *FetchDefinition) FromRequest(r *http.Request) *FetchDefinition

Use a given request to extract a path, method and body for the fetch request

func (*FetchDefinition) Hash

func (def *FetchDefinition) Hash() string

Hash returns a unique hash for the fetch request. If two hashes of fetch resources are equal, they refer the same resource and can e.g. be taken as replacement for each other. E.g. in case of caching.

func (*FetchDefinition) IsCacheable

func (def *FetchDefinition) IsCacheable(responseStatus int, responseHeaders http.Header) bool

func (*FetchDefinition) IsReadableFromCache

func (def *FetchDefinition) IsReadableFromCache() bool

func (*FetchDefinition) WithHeaders

func (fd *FetchDefinition) WithHeaders(header http.Header) *FetchDefinition

Copy headers to the fetchdefinition (but only the ones which are part of the whitelist)

func (*FetchDefinition) WithName

func (fd *FetchDefinition) WithName(name string) *FetchDefinition

Set a name to be used in the merge context later on

func (*FetchDefinition) WithPriority

func (fd *FetchDefinition) WithPriority(priority int) *FetchDefinition

Priority is used to determine which property from which head has to be taken by collision of multiple fetches

func (*FetchDefinition) WithResponseProcessor

func (fd *FetchDefinition) WithResponseProcessor(rp ResponseProcessor) *FetchDefinition

If a ResponseProcessor-Implementation is given it can be used to change the response before composition

type FetchDefinitionFactory

type FetchDefinitionFactory func(name string, params Params) (fd *FetchDefinition, existing bool, err error)

FetchDefinitionFactory should return a fetch definition for the given name and parameters. This factory method can be used to supply lazy loaded fetch jobs. The FetchDefinition returned has to have the same name as the supplied name parameter. If no fetch definition for the supplied name can be provided by the factory, existing=false is returned, otherwise existing=true.

type FetchResult

type FetchResult struct {
	Def     *FetchDefinition
	Err     error
	Content Content
	Hash    string // the hash of the FetchDefinition
}

type FetchResultSupplier

type FetchResultSupplier interface {
	// WaitForResults returns all results of a fetch job in a blocking manger.
	WaitForResults() []*FetchResult

	// MetaJSON returns the composed meta JSON object
	MetaJSON() map[string]interface{}

	// True, if no fetch jobs were added
	Empty() bool
}

type FetchResults

type FetchResults []*FetchResult

Provide implementation for sorting FetchResults by priority with sort.Sort

func (FetchResults) Len

func (fr FetchResults) Len() int

func (FetchResults) Less

func (fr FetchResults) Less(i, j int) bool

func (FetchResults) Swap

func (fr FetchResults) Swap(i, j int)

type FileContentLoader

type FileContentLoader struct {
	// contains filtered or unexported fields
}

func NewFileContentLoader

func NewFileContentLoader() *FileContentLoader

func (*FileContentLoader) Load

func (loader *FileContentLoader) Load(fd *FetchDefinition) (Content, error)

type Fragment

type Fragment interface {
	Execute(w io.Writer, data map[string]interface{}, executeNestedFragment func(nestedFragmentName string) error) error

	// MemorySize return the estimated size in bytes, for this object in memory
	MemorySize() int

	// Return the list of stylesheets used in this fragment
	Stylesheets() [][]html.Attribute
}

type HtmlContentParser

type HtmlContentParser struct {
}

func (*HtmlContentParser) Parse

func (parser *HtmlContentParser) Parse(c *MemoryContent, in io.Reader) error

type HttpContentLoader

type HttpContentLoader struct {
	// contains filtered or unexported fields
}

func NewHttpContentLoader

func NewHttpContentLoader() *HttpContentLoader

func (*HttpContentLoader) Load

func (loader *HttpContentLoader) Load(fd *FetchDefinition) (Content, error)

TODO: Should we filter the headers, which we forward here, or is it correct to copy all of them?

type IdentityDeduplicationStrategy

type IdentityDeduplicationStrategy struct {
}

NOOP strategy. This strategy will insert all found stylesheets w/o any filtering.

func (*IdentityDeduplicationStrategy) Deduplicate

func (strategy *IdentityDeduplicationStrategy) Deduplicate(stylesheets [][]html.Attribute) [][]html.Attribute

type MemoryContent

type MemoryContent struct {
	// contains filtered or unexported fields
}

func NewMemoryContent

func NewMemoryContent() *MemoryContent

func (*MemoryContent) Body

func (c *MemoryContent) Body() map[string]Fragment

func (*MemoryContent) BodyAttributes deprecated

func (c *MemoryContent) BodyAttributes() Fragment

Deprecated: This method is deprecated

func (*MemoryContent) BodyAttributesArray

func (c *MemoryContent) BodyAttributesArray() []html.Attribute

func (*MemoryContent) Dependencies

func (c *MemoryContent) Dependencies() map[string]Params

func (*MemoryContent) Head

func (c *MemoryContent) Head() Fragment

func (*MemoryContent) HttpHeader

func (c *MemoryContent) HttpHeader() http.Header

func (*MemoryContent) HttpStatusCode

func (c *MemoryContent) HttpStatusCode() int

func (*MemoryContent) MemorySize

func (c *MemoryContent) MemorySize() int

func (*MemoryContent) Meta

func (c *MemoryContent) Meta() map[string]interface{}

func (*MemoryContent) Name

func (c *MemoryContent) Name() string

func (*MemoryContent) Reader

func (c *MemoryContent) Reader() io.ReadCloser

func (*MemoryContent) RequiredContent

func (c *MemoryContent) RequiredContent() []*FetchDefinition

func (*MemoryContent) Tail

func (c *MemoryContent) Tail() Fragment

type Params

type Params map[string]string

Params is a value type for a parameter map

type ResponseProcessor

type ResponseProcessor interface {
	// Process html from responsebody before composition is triggered
	// May create a new Reader inside the ResponseBody
	Process(*http.Response, string) error
}

type SimpleDeduplicationStrategy

type SimpleDeduplicationStrategy struct {
}

Simple strategy Implements a very simple deduplication strategy. That is, it filters out stylesheets with duplicate href value.

func (*SimpleDeduplicationStrategy) Deduplicate

func (strategy *SimpleDeduplicationStrategy) Deduplicate(stylesheets [][]html.Attribute) (result [][]html.Attribute)

Remove duplicate entries from hrefs.

type StringFragment

type StringFragment struct {
	// contains filtered or unexported fields
}

StringFragment is a simple template based representation of a fragment.

func NewStringFragment

func NewStringFragment(c string) *StringFragment

func (*StringFragment) AddStylesheets

func (f *StringFragment) AddStylesheets(stylesheets [][]html.Attribute)

func (*StringFragment) Content

func (f *StringFragment) Content() string

func (*StringFragment) Execute

func (f *StringFragment) Execute(w io.Writer, data map[string]interface{}, executeNestedFragment func(nestedFragmentName string) error) error

func (*StringFragment) MemorySize

func (f *StringFragment) MemorySize() int

MemorySize return the estimated size in bytes, for this object in memory

func (*StringFragment) SetContent

func (f *StringFragment) SetContent(content string)

func (*StringFragment) Stylesheets

func (f *StringFragment) Stylesheets() [][]html.Attribute

type StylesheetDeduplicationStrategy

type StylesheetDeduplicationStrategy interface {
	Deduplicate(stylesheetAttrs [][]html.Attribute) [][]html.Attribute
}

Directories

Path Synopsis
mocks

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL