# File lib/asciidoctor/document.rb, line 1118
  def docinfo(location = :head, ext = nil)
    if safe >= SafeMode::SECURE
      ''
    else
      qualifier = (location == :footer ? '-footer' : nil)
      ext = @outfilesuffix unless ext
      docinfodir = @attributes['docinfodir']

      content = nil

      if (docinfo = @attributes['docinfo']).nil_or_empty?
        if @attributes.key? 'docinfo2'
          docinfo = ['private', 'shared']
        elsif @attributes.key? 'docinfo1'
          docinfo = ['shared']
        else
          docinfo = docinfo ? ['private'] : nil
        end
      else
        docinfo = docinfo.split(',').map(&:strip)
      end

      if docinfo
        docinfo_filename = %(docinfo#{qualifier}#{ext})
        unless (docinfo & ['shared', %(shared-#{location})]).empty?
          docinfo_path = normalize_system_path(docinfo_filename, docinfodir)
          # NOTE normalizing the lines is essential if we're performing substitutions
          if (content = read_asset(docinfo_path, :normalize => true))
            if (docinfosubs ||= resolve_docinfo_subs)
              content = (docinfosubs == :attributes) ? sub_attributes(content) : apply_subs(content, docinfosubs)
            end
          end
        end

        unless @attributes['docname'].nil_or_empty? || (docinfo & ['private', %(private-#{location})]).empty?
          docinfo_path = normalize_system_path(%(#{@attributes['docname']}-#{docinfo_filename}), docinfodir)
          # NOTE normalizing the lines is essential if we're performing substitutions
          if (content2 = read_asset(docinfo_path, :normalize => true))
            if (docinfosubs ||= resolve_docinfo_subs)
              content2 = (docinfosubs == :attributes) ? sub_attributes(content2) : apply_subs(content2, docinfosubs)
            end
            content = content ? %(#{content}#{EOL}#{content2}) : content2
          end
        end
      end

      # TODO allow document to control whether extension docinfo is contributed
      if @extensions && docinfo_processors?(location)
        contentx = @docinfo_processor_extensions[location].map {|candidate| candidate.process_method[self] }.compact * EOL
        content = content ? %(#{content}#{EOL}#{contentx}) : contentx
      end

      # coerce to string (in case the value is nil)
      %(#{content})
    end
  end